xref: /llvm-project/clang-tools-extra/unittests/clang-tidy/ModernizeModuleTest.cpp (revision 9d99cf59a151a715ebebf3a4c4782dfdb48d7f4b)
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