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 friend std::ostream &operator<<(std::ostream &Str, const Param &Value) { 53 return Str << "Matched: " << std::boolalpha << Value.Matched << ", Text: '" 54 << Value.Text << "'"; 55 } 56 }; 57 58 class MatcherTest : public ::testing::TestWithParam<Param> {}; 59 60 } // namespace 61 62 static const Param Params[] = { 63 // Accept integral literals. 64 {true, "1"}, 65 {true, "0177"}, 66 {true, "0xdeadbeef"}, 67 {true, "0b1011"}, 68 {true, "'c'"}, 69 // Reject non-integral literals. 70 {false, "1.23"}, 71 {false, "0x1p3"}, 72 {false, R"("string")"}, 73 {false, "1i"}, 74 75 // Accept literals with these unary operators. 76 {true, "-1"}, 77 {true, "+1"}, 78 {true, "~1"}, 79 {true, "!1"}, 80 // Reject invalid unary operators. 81 {false, "1-"}, 82 {false, "1+"}, 83 {false, "1~"}, 84 {false, "1!"}, 85 86 // Accept valid binary operators. 87 {true, "1+1"}, 88 {true, "1-1"}, 89 {true, "1*1"}, 90 {true, "1/1"}, 91 {true, "1%2"}, 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"}, 102 {true, "1^1"}, 103 {true, "1|1"}, 104 {true, "1&&1"}, 105 {true, "1||1"}, 106 {true, "1+ +1"}, // A space is needed to avoid being tokenized as ++ or --. 107 {true, "1- -1"}, 108 {true, "1,1"}, 109 // Reject invalid binary operators. 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 {false, "1|"}, 127 {false, "1&&"}, 128 {false, "1||"}, 129 {false, "1,"}, 130 {false, ",1"}, 131 132 // Accept valid ternary operators. 133 {true, "1?1:1"}, 134 {true, "1?:1"}, // A gcc extension treats x ? : y as x ? x : y. 135 // Reject invalid ternary operators. 136 {false, "?"}, 137 {false, "?1"}, 138 {false, "?:"}, 139 {false, "?:1"}, 140 {false, "?1:"}, 141 {false, "?1:1"}, 142 {false, "1?"}, 143 {false, "1?1"}, 144 {false, "1?:"}, 145 {false, "1?1:"}, 146 147 // Accept parenthesized expressions. 148 {true, "(1)"}, 149 {true, "((+1))"}, 150 {true, "((+(1)))"}, 151 {true, "(-1)"}, 152 {true, "-(1)"}, 153 {true, "(+1)"}, 154 {true, "((+1))"}, 155 {true, "+(1)"}, 156 {true, "(~1)"}, 157 {true, "~(1)"}, 158 {true, "(!1)"}, 159 {true, "!(1)"}, 160 {true, "(1+1)"}, 161 {true, "(1-1)"}, 162 {true, "(1*1)"}, 163 {true, "(1/1)"}, 164 {true, "(1%2)"}, 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)"}, 175 {true, "(1^1)"}, 176 {true, "(1|1)"}, 177 {true, "(1&&1)"}, 178 {true, "(1||1)"}, 179 {true, "(1?1:1)"}, 180 181 // Accept more complicated "chained" expressions. 182 {true, "1+1+1"}, 183 {true, "1+1+1+1"}, 184 {true, "1+1+1+1+1"}, 185 {true, "1*1*1"}, 186 {true, "1*1*1*1"}, 187 {true, "1*1*1*1*1"}, 188 {true, "1<<1<<1"}, 189 {true, "4U>>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 {true, "1^1^1"}, 198 {true, "1|1|1"}, 199 {true, "1&&1&&1"}, 200 {true, "1||1||1"}, 201 {true, "1,1,1"}, 202 }; 203 204 TEST_P(MatcherTest, MatchResult) { 205 EXPECT_TRUE(matchText(GetParam().Text) == GetParam().Matched); 206 } 207 208 INSTANTIATE_TEST_SUITE_P(TokenExpressionParserTests, MatcherTest, 209 ::testing::ValuesIn(Params)); 210 211 } // namespace test 212 } // namespace tidy 213 } // namespace clang 214