IntegralLiteralExpressionMatcher.cpp 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286
  1. //===--- IntegralLiteralExpressionMatcher.cpp - clang-tidy ----------------===//
  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. #include "IntegralLiteralExpressionMatcher.h"
  9. #include <algorithm>
  10. #include <cctype>
  11. #include <stdexcept>
  12. namespace clang::tidy::modernize {
  13. // Validate that this literal token is a valid integer literal. A literal token
  14. // could be a floating-point token, which isn't acceptable as a value for an
  15. // enumeration. A floating-point token must either have a decimal point or an
  16. // exponent ('E' or 'P').
  17. static bool isIntegralConstant(const Token &Token) {
  18. const char *Begin = Token.getLiteralData();
  19. const char *End = Begin + Token.getLength();
  20. // Not a hexadecimal floating-point literal.
  21. if (Token.getLength() > 2 && Begin[0] == '0' && std::toupper(Begin[1]) == 'X')
  22. return std::none_of(Begin + 2, End, [](char C) {
  23. return C == '.' || std::toupper(C) == 'P';
  24. });
  25. // Not a decimal floating-point literal or complex literal.
  26. return std::none_of(Begin, End, [](char C) {
  27. return C == '.' || std::toupper(C) == 'E' || std::toupper(C) == 'I';
  28. });
  29. }
  30. bool IntegralLiteralExpressionMatcher::advance() {
  31. ++Current;
  32. return Current != End;
  33. }
  34. bool IntegralLiteralExpressionMatcher::consume(tok::TokenKind Kind) {
  35. if (Current->is(Kind)) {
  36. ++Current;
  37. return true;
  38. }
  39. return false;
  40. }
  41. bool IntegralLiteralExpressionMatcher::nonTerminalChainedExpr(
  42. bool (IntegralLiteralExpressionMatcher::*NonTerminal)(),
  43. const std::function<bool(Token)> &IsKind) {
  44. if (!(this->*NonTerminal)())
  45. return false;
  46. if (Current == End)
  47. return true;
  48. while (Current != End) {
  49. if (!IsKind(*Current))
  50. break;
  51. if (!advance())
  52. return false;
  53. if (!(this->*NonTerminal)())
  54. return false;
  55. }
  56. return true;
  57. }
  58. // Advance over unary operators.
  59. bool IntegralLiteralExpressionMatcher::unaryOperator() {
  60. if (Current->isOneOf(tok::TokenKind::minus, tok::TokenKind::plus,
  61. tok::TokenKind::tilde, tok::TokenKind::exclaim)) {
  62. return advance();
  63. }
  64. return true;
  65. }
  66. static LiteralSize literalTokenSize(const Token &Tok) {
  67. unsigned int Length = Tok.getLength();
  68. if (Length <= 1)
  69. return LiteralSize::Int;
  70. bool SeenUnsigned = false;
  71. bool SeenLong = false;
  72. bool SeenLongLong = false;
  73. const char *Text = Tok.getLiteralData();
  74. for (unsigned int End = Length - 1; End > 0; --End) {
  75. if (std::isdigit(Text[End]))
  76. break;
  77. if (std::toupper(Text[End]) == 'U')
  78. SeenUnsigned = true;
  79. else if (std::toupper(Text[End]) == 'L') {
  80. if (SeenLong)
  81. SeenLongLong = true;
  82. SeenLong = true;
  83. }
  84. }
  85. if (SeenLongLong) {
  86. if (SeenUnsigned)
  87. return LiteralSize::UnsignedLongLong;
  88. return LiteralSize::LongLong;
  89. }
  90. if (SeenLong) {
  91. if (SeenUnsigned)
  92. return LiteralSize::UnsignedLong;
  93. return LiteralSize::Long;
  94. }
  95. if (SeenUnsigned)
  96. return LiteralSize::UnsignedInt;
  97. return LiteralSize::Int;
  98. }
  99. static bool operator<(LiteralSize LHS, LiteralSize RHS) {
  100. return static_cast<int>(LHS) < static_cast<int>(RHS);
  101. }
  102. bool IntegralLiteralExpressionMatcher::unaryExpr() {
  103. if (!unaryOperator())
  104. return false;
  105. if (consume(tok::TokenKind::l_paren)) {
  106. if (Current == End)
  107. return false;
  108. if (!expr())
  109. return false;
  110. if (Current == End)
  111. return false;
  112. return consume(tok::TokenKind::r_paren);
  113. }
  114. if (!Current->isLiteral() || isStringLiteral(Current->getKind()) ||
  115. !isIntegralConstant(*Current)) {
  116. return false;
  117. }
  118. LargestSize = std::max(LargestSize, literalTokenSize(*Current));
  119. ++Current;
  120. return true;
  121. }
  122. bool IntegralLiteralExpressionMatcher::multiplicativeExpr() {
  123. return nonTerminalChainedExpr<tok::TokenKind::star, tok::TokenKind::slash,
  124. tok::TokenKind::percent>(
  125. &IntegralLiteralExpressionMatcher::unaryExpr);
  126. }
  127. bool IntegralLiteralExpressionMatcher::additiveExpr() {
  128. return nonTerminalChainedExpr<tok::plus, tok::minus>(
  129. &IntegralLiteralExpressionMatcher::multiplicativeExpr);
  130. }
  131. bool IntegralLiteralExpressionMatcher::shiftExpr() {
  132. return nonTerminalChainedExpr<tok::TokenKind::lessless,
  133. tok::TokenKind::greatergreater>(
  134. &IntegralLiteralExpressionMatcher::additiveExpr);
  135. }
  136. bool IntegralLiteralExpressionMatcher::compareExpr() {
  137. if (!shiftExpr())
  138. return false;
  139. if (Current == End)
  140. return true;
  141. if (Current->is(tok::TokenKind::spaceship)) {
  142. if (!advance())
  143. return false;
  144. if (!shiftExpr())
  145. return false;
  146. }
  147. return true;
  148. }
  149. bool IntegralLiteralExpressionMatcher::relationalExpr() {
  150. return nonTerminalChainedExpr<tok::TokenKind::less, tok::TokenKind::greater,
  151. tok::TokenKind::lessequal,
  152. tok::TokenKind::greaterequal>(
  153. &IntegralLiteralExpressionMatcher::compareExpr);
  154. }
  155. bool IntegralLiteralExpressionMatcher::equalityExpr() {
  156. return nonTerminalChainedExpr<tok::TokenKind::equalequal,
  157. tok::TokenKind::exclaimequal>(
  158. &IntegralLiteralExpressionMatcher::relationalExpr);
  159. }
  160. bool IntegralLiteralExpressionMatcher::andExpr() {
  161. return nonTerminalChainedExpr<tok::TokenKind::amp>(
  162. &IntegralLiteralExpressionMatcher::equalityExpr);
  163. }
  164. bool IntegralLiteralExpressionMatcher::exclusiveOrExpr() {
  165. return nonTerminalChainedExpr<tok::TokenKind::caret>(
  166. &IntegralLiteralExpressionMatcher::andExpr);
  167. }
  168. bool IntegralLiteralExpressionMatcher::inclusiveOrExpr() {
  169. return nonTerminalChainedExpr<tok::TokenKind::pipe>(
  170. &IntegralLiteralExpressionMatcher::exclusiveOrExpr);
  171. }
  172. bool IntegralLiteralExpressionMatcher::logicalAndExpr() {
  173. return nonTerminalChainedExpr<tok::TokenKind::ampamp>(
  174. &IntegralLiteralExpressionMatcher::inclusiveOrExpr);
  175. }
  176. bool IntegralLiteralExpressionMatcher::logicalOrExpr() {
  177. return nonTerminalChainedExpr<tok::TokenKind::pipepipe>(
  178. &IntegralLiteralExpressionMatcher::logicalAndExpr);
  179. }
  180. bool IntegralLiteralExpressionMatcher::conditionalExpr() {
  181. if (!logicalOrExpr())
  182. return false;
  183. if (Current == End)
  184. return true;
  185. if (Current->is(tok::TokenKind::question)) {
  186. if (!advance())
  187. return false;
  188. // A gcc extension allows x ? : y as a synonym for x ? x : y.
  189. if (Current->is(tok::TokenKind::colon)) {
  190. if (!advance())
  191. return false;
  192. if (!expr())
  193. return false;
  194. return true;
  195. }
  196. if (!expr())
  197. return false;
  198. if (Current == End)
  199. return false;
  200. if (!Current->is(tok::TokenKind::colon))
  201. return false;
  202. if (!advance())
  203. return false;
  204. if (!expr())
  205. return false;
  206. }
  207. return true;
  208. }
  209. bool IntegralLiteralExpressionMatcher::commaExpr() {
  210. auto Pred = CommaAllowed
  211. ? std::function<bool(Token)>(
  212. [](Token Tok) { return Tok.is(tok::TokenKind::comma); })
  213. : std::function<bool(Token)>([](Token) { return false; });
  214. return nonTerminalChainedExpr(
  215. &IntegralLiteralExpressionMatcher::conditionalExpr, Pred);
  216. }
  217. bool IntegralLiteralExpressionMatcher::expr() { return commaExpr(); }
  218. bool IntegralLiteralExpressionMatcher::match() {
  219. // Top-level allowed expression is conditionalExpr(), not expr(), because
  220. // comma operators are only valid initializers when used inside parentheses.
  221. return conditionalExpr() && Current == End;
  222. }
  223. LiteralSize IntegralLiteralExpressionMatcher::largestLiteralSize() const {
  224. return LargestSize;
  225. }
  226. } // namespace clang::tidy::modernize