1 //===---- ModernizeModuleTest.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 "ClangTidyTest.h" 9 #include "modernize/IntegralLiteralExpressionMatcher.h" 10 #include "clang/Lex/Lexer.h" 11 #include "gtest/gtest.h" 12 13 #include <cstring> 14 #include <iterator> 15 #include <string> 16 #include <vector> 17 18 namespace clang { 19 namespace tidy { 20 namespace test { 21 22 static std::vector<Token> tokenify(const char *Text) { 23 LangOptions LangOpts; 24 std::vector<std::string> Includes; 25 LangOptions::setLangDefaults(LangOpts, Language::CXX, llvm::Triple(), 26 Includes, LangStandard::lang_cxx20); 27 Lexer Lex(SourceLocation{}, LangOpts, Text, Text, Text + std::strlen(Text)); 28 std::vector<Token> Tokens; 29 bool End = false; 30 while (!End) { 31 Token Tok; 32 End = Lex.LexFromRawLexer(Tok); 33 Tokens.push_back(Tok); 34 } 35 36 return Tokens; 37 } 38 39 static bool matchText(const char *Text) { 40 std::vector<Token> Tokens{tokenify(Text)}; 41 modernize::IntegralLiteralExpressionMatcher Matcher(Tokens); 42 43 return Matcher.match(); 44 } 45 46 namespace { 47 48 struct Param { 49 bool Matched; 50 const char *Text; 51 }; 52 53 class MatcherTest : public ::testing::TestWithParam<Param> {}; 54 55 } // namespace 56 57 static const Param Params[] = { 58 // Accept integral literals. 59 {true, "1"}, 60 {true, "0177"}, 61 {true, "0xdeadbeef"}, 62 {true, "0b1011"}, 63 {true, "'c'"}, 64 // Reject non-integral literals. 65 {false, "1.23"}, 66 {false, "0x1p3"}, 67 {false, R"("string")"}, 68 {false, "1i"}, 69 70 // Accept literals with these unary operators. 71 {true, "-1"}, 72 {true, "+1"}, 73 {true, "~1"}, 74 {true, "!1"}, 75 // Reject invalid unary operators. 76 {false, "1-"}, 77 {false, "1+"}, 78 {false, "1~"}, 79 {false, "1!"}, 80 81 // Accept valid binary operators. 82 {true, "1+1"}, 83 {true, "1-1"}, 84 {true, "1*1"}, 85 {true, "1/1"}, 86 {true, "1%2"}, 87 {true, "1<<1"}, 88 {true, "1>>1"}, 89 {true, "1<=>1"}, 90 {true, "1<1"}, 91 {true, "1>1"}, 92 {true, "1<=1"}, 93 {true, "1>=1"}, 94 {true, "1==1"}, 95 {true, "1!=1"}, 96 {true, "1&1"}, 97 {true, "1^1"}, 98 {true, "1|1"}, 99 {true, "1&&1"}, 100 {true, "1||1"}, 101 {true, "1+ +1"}, // A space is needed to avoid being tokenized as ++ or --. 102 {true, "1- -1"}, 103 {true, "1,1"}, 104 // Reject invalid binary operators. 105 {false, "1+"}, 106 {false, "1-"}, 107 {false, "1*"}, 108 {false, "1/"}, 109 {false, "1%"}, 110 {false, "1<<"}, 111 {false, "1>>"}, 112 {false, "1<=>"}, 113 {false, "1<"}, 114 {false, "1>"}, 115 {false, "1<="}, 116 {false, "1>="}, 117 {false, "1=="}, 118 {false, "1!="}, 119 {false, "1&"}, 120 {false, "1^"}, 121 {false, "1|"}, 122 {false, "1&&"}, 123 {false, "1||"}, 124 {false, "1,"}, 125 {false, ",1"}, 126 127 // Accept valid ternary operators. 128 {true, "1?1:1"}, 129 {true, "1?:1"}, // A gcc extension treats x ? : y as x ? x : y. 130 // Reject invalid ternary operators. 131 {false, "?"}, 132 {false, "?1"}, 133 {false, "?:"}, 134 {false, "?:1"}, 135 {false, "?1:"}, 136 {false, "?1:1"}, 137 {false, "1?"}, 138 {false, "1?1"}, 139 {false, "1?:"}, 140 {false, "1?1:"}, 141 142 // Accept parenthesized expressions. 143 {true, "(1)"}, 144 {true, "((+1))"}, 145 {true, "((+(1)))"}, 146 {true, "(-1)"}, 147 {true, "-(1)"}, 148 {true, "(+1)"}, 149 {true, "((+1))"}, 150 {true, "+(1)"}, 151 {true, "(~1)"}, 152 {true, "~(1)"}, 153 {true, "(!1)"}, 154 {true, "!(1)"}, 155 {true, "(1+1)"}, 156 {true, "(1-1)"}, 157 {true, "(1*1)"}, 158 {true, "(1/1)"}, 159 {true, "(1%2)"}, 160 {true, "(1<<1)"}, 161 {true, "(1>>1)"}, 162 {true, "(1<=>1)"}, 163 {true, "(1<1)"}, 164 {true, "(1>1)"}, 165 {true, "(1<=1)"}, 166 {true, "(1>=1)"}, 167 {true, "(1==1)"}, 168 {true, "(1!=1)"}, 169 {true, "(1&1)"}, 170 {true, "(1^1)"}, 171 {true, "(1|1)"}, 172 {true, "(1&&1)"}, 173 {true, "(1||1)"}, 174 {true, "(1?1:1)"}, 175 176 // Accept more complicated "chained" expressions. 177 {true, "1+1+1"}, 178 {true, "1+1+1+1"}, 179 {true, "1+1+1+1+1"}, 180 {true, "1*1*1"}, 181 {true, "1*1*1*1"}, 182 {true, "1*1*1*1*1"}, 183 {true, "1<<1<<1"}, 184 {true, "4U>>1>>1"}, 185 {true, "1<1<1"}, 186 {true, "1>1>1"}, 187 {true, "1<=1<=1"}, 188 {true, "1>=1>=1"}, 189 {true, "1==1==1"}, 190 {true, "1!=1!=1"}, 191 {true, "1&1&1"}, 192 {true, "1^1^1"}, 193 {true, "1|1|1"}, 194 {true, "1&&1&&1"}, 195 {true, "1||1||1"}, 196 {true, "1,1,1"}, 197 }; 198 199 TEST_P(MatcherTest, MatchResult) { 200 EXPECT_TRUE(matchText(GetParam().Text) == GetParam().Matched); 201 } 202 203 INSTANTIATE_TEST_SUITE_P(TokenExpressionParserTests, MatcherTest, 204 ::testing::ValuesIn(Params)); 205 206 } // namespace test 207 } // namespace tidy 208 } // namespace clang 209