151227383SRichard //===---- ModernizeModuleTest.cpp - clang-tidy ----------------------------===//
251227383SRichard //
351227383SRichard // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
451227383SRichard // See https://llvm.org/LICENSE.txt for license information.
551227383SRichard // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
651227383SRichard //
751227383SRichard //===----------------------------------------------------------------------===//
851227383SRichard #include "ClangTidyTest.h"
951227383SRichard #include "modernize/IntegralLiteralExpressionMatcher.h"
1051227383SRichard #include "clang/Lex/Lexer.h"
1151227383SRichard #include "gtest/gtest.h"
1251227383SRichard
1351227383SRichard #include <cstring>
1451227383SRichard #include <iterator>
1551227383SRichard #include <string>
1651227383SRichard #include <vector>
1751227383SRichard
1851227383SRichard namespace clang {
1951227383SRichard namespace tidy {
2051227383SRichard namespace test {
2151227383SRichard
tokenify(const char * Text)2251227383SRichard static std::vector<Token> tokenify(const char *Text) {
2351227383SRichard LangOptions LangOpts;
2451227383SRichard std::vector<std::string> Includes;
2551227383SRichard LangOptions::setLangDefaults(LangOpts, Language::CXX, llvm::Triple(),
2651227383SRichard Includes, LangStandard::lang_cxx20);
2751227383SRichard Lexer Lex(SourceLocation{}, LangOpts, Text, Text, Text + std::strlen(Text));
2851227383SRichard std::vector<Token> Tokens;
2951227383SRichard bool End = false;
3051227383SRichard while (!End) {
3151227383SRichard Token Tok;
3251227383SRichard End = Lex.LexFromRawLexer(Tok);
3351227383SRichard Tokens.push_back(Tok);
3451227383SRichard }
3551227383SRichard
3651227383SRichard return Tokens;
3751227383SRichard }
3851227383SRichard
matchText(const char * Text,bool AllowComma)39b418ef5cSRichard static bool matchText(const char *Text, bool AllowComma) {
4051227383SRichard std::vector<Token> Tokens{tokenify(Text)};
41b418ef5cSRichard modernize::IntegralLiteralExpressionMatcher Matcher(Tokens, AllowComma);
4251227383SRichard
4351227383SRichard return Matcher.match();
4451227383SRichard }
4551227383SRichard
sizeText(const char * Text)46b418ef5cSRichard static modernize::LiteralSize sizeText(const char *Text) {
47b418ef5cSRichard std::vector<Token> Tokens{tokenify(Text)};
48b418ef5cSRichard modernize::IntegralLiteralExpressionMatcher Matcher(Tokens, true);
49b418ef5cSRichard if (Matcher.match())
50b418ef5cSRichard return Matcher.largestLiteralSize();
51b418ef5cSRichard return modernize::LiteralSize::Unknown;
52b418ef5cSRichard }
53b418ef5cSRichard
toString(modernize::LiteralSize Value)54b418ef5cSRichard static const char *toString(modernize::LiteralSize Value) {
55b418ef5cSRichard switch (Value) {
56b418ef5cSRichard case modernize::LiteralSize::Int:
57b418ef5cSRichard return "Int";
58b418ef5cSRichard case modernize::LiteralSize::UnsignedInt:
59b418ef5cSRichard return "UnsignedInt";
60b418ef5cSRichard case modernize::LiteralSize::Long:
61b418ef5cSRichard return "Long";
62b418ef5cSRichard case modernize::LiteralSize::UnsignedLong:
63b418ef5cSRichard return "UnsignedLong";
64b418ef5cSRichard case modernize::LiteralSize::LongLong:
65b418ef5cSRichard return "LongLong";
66b418ef5cSRichard case modernize::LiteralSize::UnsignedLongLong:
67b418ef5cSRichard return "UnsignedLongLong";
68b418ef5cSRichard default:
69b418ef5cSRichard return "Unknown";
70b418ef5cSRichard }
71b418ef5cSRichard }
72b418ef5cSRichard
7351227383SRichard namespace {
7451227383SRichard
75b418ef5cSRichard struct MatchParam {
76b418ef5cSRichard bool AllowComma;
7751227383SRichard bool Matched;
7851227383SRichard const char *Text;
799d99cf59SRichard
operator <<(std::ostream & Str,const MatchParam & Value)80b418ef5cSRichard friend std::ostream &operator<<(std::ostream &Str, const MatchParam &Value) {
81b418ef5cSRichard return Str << "Allow operator,: " << std::boolalpha << Value.AllowComma
82b418ef5cSRichard << ", Matched: " << std::boolalpha << Value.Matched
83b418ef5cSRichard << ", Text: '" << Value.Text << '\'';
849d99cf59SRichard }
8551227383SRichard };
8651227383SRichard
87b418ef5cSRichard struct SizeParam {
88b418ef5cSRichard modernize::LiteralSize Size;
89b418ef5cSRichard const char *Text;
90b418ef5cSRichard
operator <<(std::ostream & Str,const SizeParam & Value)91b418ef5cSRichard friend std::ostream &operator<<(std::ostream &Str, const SizeParam &Value) {
92b418ef5cSRichard return Str << "Size: " << toString(Value.Size) << ", Text: '" << Value.Text << '\'';
93b418ef5cSRichard }
94b418ef5cSRichard };
95b418ef5cSRichard
96b418ef5cSRichard class MatcherTest : public ::testing::TestWithParam<MatchParam> {};
97b418ef5cSRichard
98b418ef5cSRichard class SizeTest : public ::testing::TestWithParam<SizeParam> {};
9951227383SRichard
10051227383SRichard } // namespace
10151227383SRichard
102b418ef5cSRichard static const MatchParam MatchParams[] = {
10351227383SRichard // Accept integral literals.
104b418ef5cSRichard {true, true, "1"},
105b418ef5cSRichard {true, true, "0177"},
106b418ef5cSRichard {true, true, "0xdeadbeef"},
107b418ef5cSRichard {true, true, "0b1011"},
108b418ef5cSRichard {true, true, "'c'"},
10951227383SRichard // Reject non-integral literals.
110b418ef5cSRichard {true, false, "1.23"},
111b418ef5cSRichard {true, false, "0x1p3"},
112b418ef5cSRichard {true, false, R"("string")"},
113b418ef5cSRichard {true, false, "1i"},
11451227383SRichard
11551227383SRichard // Accept literals with these unary operators.
116b418ef5cSRichard {true, true, "-1"},
117b418ef5cSRichard {true, true, "+1"},
118b418ef5cSRichard {true, true, "~1"},
119b418ef5cSRichard {true, true, "!1"},
12051227383SRichard // Reject invalid unary operators.
121b418ef5cSRichard {true, false, "1-"},
122b418ef5cSRichard {true, false, "1+"},
123b418ef5cSRichard {true, false, "1~"},
124b418ef5cSRichard {true, false, "1!"},
12551227383SRichard
12651227383SRichard // Accept valid binary operators.
127b418ef5cSRichard {true, true, "1+1"},
128b418ef5cSRichard {true, true, "1-1"},
129b418ef5cSRichard {true, true, "1*1"},
130b418ef5cSRichard {true, true, "1/1"},
131b418ef5cSRichard {true, true, "1%2"},
132b418ef5cSRichard {true, true, "1<<1"},
133b418ef5cSRichard {true, true, "1>>1"},
134b418ef5cSRichard {true, true, "1<=>1"},
135b418ef5cSRichard {true, true, "1<1"},
136b418ef5cSRichard {true, true, "1>1"},
137b418ef5cSRichard {true, true, "1<=1"},
138b418ef5cSRichard {true, true, "1>=1"},
139b418ef5cSRichard {true, true, "1==1"},
140b418ef5cSRichard {true, true, "1!=1"},
141b418ef5cSRichard {true, true, "1&1"},
142b418ef5cSRichard {true, true, "1^1"},
143b418ef5cSRichard {true, true, "1|1"},
144b418ef5cSRichard {true, true, "1&&1"},
145b418ef5cSRichard {true, true, "1||1"},
146b418ef5cSRichard {true, true, "1+ +1"}, // A space is needed to avoid being tokenized as ++ or --.
147b418ef5cSRichard {true, true, "1- -1"},
148b418ef5cSRichard // Comma is only valid when inside parentheses.
149b418ef5cSRichard {true, true, "(1,1)"},
15051227383SRichard // Reject invalid binary operators.
151b418ef5cSRichard {true, false, "1+"},
152b418ef5cSRichard {true, false, "1-"},
153b418ef5cSRichard {true, false, "1*"},
154b418ef5cSRichard {true, false, "1/"},
155b418ef5cSRichard {true, false, "1%"},
156b418ef5cSRichard {true, false, "1<<"},
157b418ef5cSRichard {true, false, "1>>"},
158b418ef5cSRichard {true, false, "1<=>"},
159b418ef5cSRichard {true, false, "1<"},
160b418ef5cSRichard {true, false, "1>"},
161b418ef5cSRichard {true, false, "1<="},
162b418ef5cSRichard {true, false, "1>="},
163b418ef5cSRichard {true, false, "1=="},
164b418ef5cSRichard {true, false, "1!="},
165b418ef5cSRichard {true, false, "1&"},
166b418ef5cSRichard {true, false, "1^"},
167b418ef5cSRichard {true, false, "1|"},
168b418ef5cSRichard {true, false, "1&&"},
169b418ef5cSRichard {true, false, "1||"},
170b418ef5cSRichard {true, false, "1,"},
171b418ef5cSRichard {true, false, ",1"},
172b418ef5cSRichard {true, false, "1,1"},
17351227383SRichard
17451227383SRichard // Accept valid ternary operators.
175b418ef5cSRichard {true, true, "1?1:1"},
176b418ef5cSRichard {true, true, "1?:1"}, // A gcc extension treats x ? : y as x ? x : y.
17751227383SRichard // Reject invalid ternary operators.
178b418ef5cSRichard {true, false, "?"},
179b418ef5cSRichard {true, false, "?1"},
180b418ef5cSRichard {true, false, "?:"},
181b418ef5cSRichard {true, false, "?:1"},
182b418ef5cSRichard {true, false, "?1:"},
183b418ef5cSRichard {true, false, "?1:1"},
184b418ef5cSRichard {true, false, "1?"},
185b418ef5cSRichard {true, false, "1?1"},
186b418ef5cSRichard {true, false, "1?:"},
187b418ef5cSRichard {true, false, "1?1:"},
18851227383SRichard
18951227383SRichard // Accept parenthesized expressions.
190b418ef5cSRichard {true, true, "(1)"},
191b418ef5cSRichard {true, true, "((+1))"},
192b418ef5cSRichard {true, true, "((+(1)))"},
193b418ef5cSRichard {true, true, "(-1)"},
194b418ef5cSRichard {true, true, "-(1)"},
195b418ef5cSRichard {true, true, "(+1)"},
196b418ef5cSRichard {true, true, "((+1))"},
197b418ef5cSRichard {true, true, "+(1)"},
198b418ef5cSRichard {true, true, "(~1)"},
199b418ef5cSRichard {true, true, "~(1)"},
200b418ef5cSRichard {true, true, "(!1)"},
201b418ef5cSRichard {true, true, "!(1)"},
202b418ef5cSRichard {true, true, "(1+1)"},
203b418ef5cSRichard {true, true, "(1-1)"},
204b418ef5cSRichard {true, true, "(1*1)"},
205b418ef5cSRichard {true, true, "(1/1)"},
206b418ef5cSRichard {true, true, "(1%2)"},
207b418ef5cSRichard {true, true, "(1<<1)"},
208b418ef5cSRichard {true, true, "(1>>1)"},
209b418ef5cSRichard {true, true, "(1<=>1)"},
210b418ef5cSRichard {true, true, "(1<1)"},
211b418ef5cSRichard {true, true, "(1>1)"},
212b418ef5cSRichard {true, true, "(1<=1)"},
213b418ef5cSRichard {true, true, "(1>=1)"},
214b418ef5cSRichard {true, true, "(1==1)"},
215b418ef5cSRichard {true, true, "(1!=1)"},
216b418ef5cSRichard {true, true, "(1&1)"},
217b418ef5cSRichard {true, true, "(1^1)"},
218b418ef5cSRichard {true, true, "(1|1)"},
219b418ef5cSRichard {true, true, "(1&&1)"},
220b418ef5cSRichard {true, true, "(1||1)"},
221b418ef5cSRichard {true, true, "(1?1:1)"},
22251227383SRichard
22351227383SRichard // Accept more complicated "chained" expressions.
224b418ef5cSRichard {true, true, "1+1+1"},
225b418ef5cSRichard {true, true, "1+1+1+1"},
226b418ef5cSRichard {true, true, "1+1+1+1+1"},
227b418ef5cSRichard {true, true, "1*1*1"},
228b418ef5cSRichard {true, true, "1*1*1*1"},
229b418ef5cSRichard {true, true, "1*1*1*1*1"},
230b418ef5cSRichard {true, true, "1<<1<<1"},
231b418ef5cSRichard {true, true, "4U>>1>>1"},
232b418ef5cSRichard {true, true, "1<1<1"},
233b418ef5cSRichard {true, true, "1>1>1"},
234b418ef5cSRichard {true, true, "1<=1<=1"},
235b418ef5cSRichard {true, true, "1>=1>=1"},
236b418ef5cSRichard {true, true, "1==1==1"},
237b418ef5cSRichard {true, true, "1!=1!=1"},
238b418ef5cSRichard {true, true, "1&1&1"},
239b418ef5cSRichard {true, true, "1^1^1"},
240b418ef5cSRichard {true, true, "1|1|1"},
241b418ef5cSRichard {true, true, "1&&1&&1"},
242b418ef5cSRichard {true, true, "1||1||1"},
243b418ef5cSRichard {true, true, "(1,1,1)"},
244b418ef5cSRichard
245b418ef5cSRichard // Optionally reject comma operator
246b418ef5cSRichard {false, false, "1,1"}
24751227383SRichard };
24851227383SRichard
TEST_P(MatcherTest,MatchResult)24951227383SRichard TEST_P(MatcherTest, MatchResult) {
250b418ef5cSRichard const MatchParam &Param = GetParam();
251b418ef5cSRichard
252b418ef5cSRichard EXPECT_TRUE(matchText(Param.Text, Param.AllowComma) == Param.Matched);
25351227383SRichard }
25451227383SRichard
255b418ef5cSRichard INSTANTIATE_TEST_SUITE_P(IntegralLiteralExpressionMatcherTests, MatcherTest,
256b418ef5cSRichard ::testing::ValuesIn(MatchParams));
257b418ef5cSRichard
258b418ef5cSRichard static const SizeParam SizeParams[] = {
259b418ef5cSRichard {modernize::LiteralSize::Int, "1"},
260b418ef5cSRichard {modernize::LiteralSize::UnsignedInt, "1U"},
261b418ef5cSRichard {modernize::LiteralSize::Long, "1L"},
262b418ef5cSRichard {modernize::LiteralSize::UnsignedLong, "1UL"},
263b418ef5cSRichard {modernize::LiteralSize::UnsignedLong, "1LU"},
264b418ef5cSRichard {modernize::LiteralSize::LongLong, "1LL"},
265b418ef5cSRichard {modernize::LiteralSize::UnsignedLongLong, "1ULL"},
266b418ef5cSRichard {modernize::LiteralSize::UnsignedLongLong, "1LLU"}};
267b418ef5cSRichard
TEST_P(SizeTest,TokenSize)268b418ef5cSRichard TEST_P(SizeTest, TokenSize) {
269b418ef5cSRichard EXPECT_EQ(sizeText(GetParam().Text), GetParam().Size);
270*35f0890cSMikael Holmen }
271b418ef5cSRichard
272b418ef5cSRichard INSTANTIATE_TEST_SUITE_P(IntegralLiteralExpressionMatcherTests, SizeTest,
273b418ef5cSRichard ::testing::ValuesIn(SizeParams));
27451227383SRichard
27551227383SRichard } // namespace test
27651227383SRichard } // namespace tidy
27751227383SRichard } // namespace clang
278