278 lines
		
	
	
		
			7.8 KiB
		
	
	
	
		
			C++
		
	
	
	
			
		
		
	
	
			278 lines
		
	
	
		
			7.8 KiB
		
	
	
	
		
			C++
		
	
	
	
| //===---- ModernizeModuleTest.cpp - clang-tidy ----------------------------===//
 | |
| //
 | |
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
 | |
| // See https://llvm.org/LICENSE.txt for license information.
 | |
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
 | |
| //
 | |
| //===----------------------------------------------------------------------===//
 | |
| #include "ClangTidyTest.h"
 | |
| #include "modernize/IntegralLiteralExpressionMatcher.h"
 | |
| #include "clang/Lex/Lexer.h"
 | |
| #include "gtest/gtest.h"
 | |
| 
 | |
| #include <cstring>
 | |
| #include <iterator>
 | |
| #include <string>
 | |
| #include <vector>
 | |
| 
 | |
| namespace clang {
 | |
| namespace tidy {
 | |
| namespace test {
 | |
| 
 | |
| static std::vector<Token> tokenify(const char *Text) {
 | |
|   LangOptions LangOpts;
 | |
|   std::vector<std::string> Includes;
 | |
|   LangOptions::setLangDefaults(LangOpts, Language::CXX, llvm::Triple(),
 | |
|                                Includes, LangStandard::lang_cxx20);
 | |
|   Lexer Lex(SourceLocation{}, LangOpts, Text, Text, Text + std::strlen(Text));
 | |
|   std::vector<Token> Tokens;
 | |
|   bool End = false;
 | |
|   while (!End) {
 | |
|     Token Tok;
 | |
|     End = Lex.LexFromRawLexer(Tok);
 | |
|     Tokens.push_back(Tok);
 | |
|   }
 | |
| 
 | |
|   return Tokens;
 | |
| }
 | |
| 
 | |
| static bool matchText(const char *Text, bool AllowComma) {
 | |
|   std::vector<Token> Tokens{tokenify(Text)};
 | |
|   modernize::IntegralLiteralExpressionMatcher Matcher(Tokens, AllowComma);
 | |
| 
 | |
|   return Matcher.match();
 | |
| }
 | |
| 
 | |
| static modernize::LiteralSize sizeText(const char *Text) {
 | |
|   std::vector<Token> Tokens{tokenify(Text)};
 | |
|   modernize::IntegralLiteralExpressionMatcher Matcher(Tokens, true);
 | |
|   if (Matcher.match())
 | |
|     return Matcher.largestLiteralSize();
 | |
|   return modernize::LiteralSize::Unknown;
 | |
| }
 | |
| 
 | |
| static const char *toString(modernize::LiteralSize Value) {
 | |
|   switch (Value) {
 | |
|   case modernize::LiteralSize::Int:
 | |
|     return "Int";
 | |
|   case modernize::LiteralSize::UnsignedInt:
 | |
|     return "UnsignedInt";
 | |
|   case modernize::LiteralSize::Long:
 | |
|     return "Long";
 | |
|   case modernize::LiteralSize::UnsignedLong:
 | |
|     return "UnsignedLong";
 | |
|   case modernize::LiteralSize::LongLong:
 | |
|     return "LongLong";
 | |
|   case modernize::LiteralSize::UnsignedLongLong:
 | |
|     return "UnsignedLongLong";
 | |
|   default:
 | |
|     return "Unknown";
 | |
|   }
 | |
| }
 | |
| 
 | |
| namespace {
 | |
| 
 | |
| struct MatchParam {
 | |
|   bool AllowComma;
 | |
|   bool Matched;
 | |
|   const char *Text;
 | |
| 
 | |
|   friend std::ostream &operator<<(std::ostream &Str, const MatchParam &Value) {
 | |
|     return Str << "Allow operator,: " << std::boolalpha << Value.AllowComma
 | |
|                << ", Matched: " << std::boolalpha << Value.Matched
 | |
|                << ", Text: '" << Value.Text << '\'';
 | |
|   }
 | |
| };
 | |
| 
 | |
| struct SizeParam {
 | |
|   modernize::LiteralSize Size;
 | |
|   const char *Text;
 | |
| 
 | |
|   friend std::ostream &operator<<(std::ostream &Str, const SizeParam &Value) {
 | |
|     return Str << "Size: " << toString(Value.Size) << ", Text: '" << Value.Text << '\'';
 | |
|   }
 | |
| };
 | |
| 
 | |
| class MatcherTest : public ::testing::TestWithParam<MatchParam> {};
 | |
| 
 | |
| class SizeTest : public ::testing::TestWithParam<SizeParam> {};
 | |
| 
 | |
| } // namespace
 | |
| 
 | |
| static const MatchParam MatchParams[] = {
 | |
|     // Accept integral literals.
 | |
|     {true, true, "1"},
 | |
|     {true, true, "0177"},
 | |
|     {true, true, "0xdeadbeef"},
 | |
|     {true, true, "0b1011"},
 | |
|     {true, true, "'c'"},
 | |
|     // Reject non-integral literals.
 | |
|     {true, false, "1.23"},
 | |
|     {true, false, "0x1p3"},
 | |
|     {true, false, R"("string")"},
 | |
|     {true, false, "1i"},
 | |
| 
 | |
|     // Accept literals with these unary operators.
 | |
|     {true, true, "-1"},
 | |
|     {true, true, "+1"},
 | |
|     {true, true, "~1"},
 | |
|     {true, true, "!1"},
 | |
|     // Reject invalid unary operators.
 | |
|     {true, false, "1-"},
 | |
|     {true, false, "1+"},
 | |
|     {true, false, "1~"},
 | |
|     {true, false, "1!"},
 | |
| 
 | |
|     // Accept valid binary operators.
 | |
|     {true, true, "1+1"},
 | |
|     {true, true, "1-1"},
 | |
|     {true, true, "1*1"},
 | |
|     {true, true, "1/1"},
 | |
|     {true, true, "1%2"},
 | |
|     {true, true, "1<<1"},
 | |
|     {true, true, "1>>1"},
 | |
|     {true, true, "1<=>1"},
 | |
|     {true, true, "1<1"},
 | |
|     {true, true, "1>1"},
 | |
|     {true, true, "1<=1"},
 | |
|     {true, true, "1>=1"},
 | |
|     {true, true, "1==1"},
 | |
|     {true, true, "1!=1"},
 | |
|     {true, true, "1&1"},
 | |
|     {true, true, "1^1"},
 | |
|     {true, true, "1|1"},
 | |
|     {true, true, "1&&1"},
 | |
|     {true, true, "1||1"},
 | |
|     {true, true, "1+ +1"}, // A space is needed to avoid being tokenized as ++ or --.
 | |
|     {true, true, "1- -1"},
 | |
|     // Comma is only valid when inside parentheses.
 | |
|     {true, true, "(1,1)"},
 | |
|     // Reject invalid binary operators.
 | |
|     {true, false, "1+"},
 | |
|     {true, false, "1-"},
 | |
|     {true, false, "1*"},
 | |
|     {true, false, "1/"},
 | |
|     {true, false, "1%"},
 | |
|     {true, false, "1<<"},
 | |
|     {true, false, "1>>"},
 | |
|     {true, false, "1<=>"},
 | |
|     {true, false, "1<"},
 | |
|     {true, false, "1>"},
 | |
|     {true, false, "1<="},
 | |
|     {true, false, "1>="},
 | |
|     {true, false, "1=="},
 | |
|     {true, false, "1!="},
 | |
|     {true, false, "1&"},
 | |
|     {true, false, "1^"},
 | |
|     {true, false, "1|"},
 | |
|     {true, false, "1&&"},
 | |
|     {true, false, "1||"},
 | |
|     {true, false, "1,"},
 | |
|     {true, false, ",1"},
 | |
|     {true, false, "1,1"},
 | |
| 
 | |
|     // Accept valid ternary operators.
 | |
|     {true, true, "1?1:1"},
 | |
|     {true, true, "1?:1"}, // A gcc extension treats x ? : y as x ? x : y.
 | |
|     // Reject invalid ternary operators.
 | |
|     {true, false, "?"},
 | |
|     {true, false, "?1"},
 | |
|     {true, false, "?:"},
 | |
|     {true, false, "?:1"},
 | |
|     {true, false, "?1:"},
 | |
|     {true, false, "?1:1"},
 | |
|     {true, false, "1?"},
 | |
|     {true, false, "1?1"},
 | |
|     {true, false, "1?:"},
 | |
|     {true, false, "1?1:"},
 | |
| 
 | |
|     // Accept parenthesized expressions.
 | |
|     {true, true, "(1)"},
 | |
|     {true, true, "((+1))"},
 | |
|     {true, true, "((+(1)))"},
 | |
|     {true, true, "(-1)"},
 | |
|     {true, true, "-(1)"},
 | |
|     {true, true, "(+1)"},
 | |
|     {true, true, "((+1))"},
 | |
|     {true, true, "+(1)"},
 | |
|     {true, true, "(~1)"},
 | |
|     {true, true, "~(1)"},
 | |
|     {true, true, "(!1)"},
 | |
|     {true, true, "!(1)"},
 | |
|     {true, true, "(1+1)"},
 | |
|     {true, true, "(1-1)"},
 | |
|     {true, true, "(1*1)"},
 | |
|     {true, true, "(1/1)"},
 | |
|     {true, true, "(1%2)"},
 | |
|     {true, true, "(1<<1)"},
 | |
|     {true, true, "(1>>1)"},
 | |
|     {true, true, "(1<=>1)"},
 | |
|     {true, true, "(1<1)"},
 | |
|     {true, true, "(1>1)"},
 | |
|     {true, true, "(1<=1)"},
 | |
|     {true, true, "(1>=1)"},
 | |
|     {true, true, "(1==1)"},
 | |
|     {true, true, "(1!=1)"},
 | |
|     {true, true, "(1&1)"},
 | |
|     {true, true, "(1^1)"},
 | |
|     {true, true, "(1|1)"},
 | |
|     {true, true, "(1&&1)"},
 | |
|     {true, true, "(1||1)"},
 | |
|     {true, true, "(1?1:1)"},
 | |
| 
 | |
|     // Accept more complicated "chained" expressions.
 | |
|     {true, true, "1+1+1"},
 | |
|     {true, true, "1+1+1+1"},
 | |
|     {true, true, "1+1+1+1+1"},
 | |
|     {true, true, "1*1*1"},
 | |
|     {true, true, "1*1*1*1"},
 | |
|     {true, true, "1*1*1*1*1"},
 | |
|     {true, true, "1<<1<<1"},
 | |
|     {true, true, "4U>>1>>1"},
 | |
|     {true, true, "1<1<1"},
 | |
|     {true, true, "1>1>1"},
 | |
|     {true, true, "1<=1<=1"},
 | |
|     {true, true, "1>=1>=1"},
 | |
|     {true, true, "1==1==1"},
 | |
|     {true, true, "1!=1!=1"},
 | |
|     {true, true, "1&1&1"},
 | |
|     {true, true, "1^1^1"},
 | |
|     {true, true, "1|1|1"},
 | |
|     {true, true, "1&&1&&1"},
 | |
|     {true, true, "1||1||1"},
 | |
|     {true, true, "(1,1,1)"},
 | |
| 
 | |
|     // Optionally reject comma operator
 | |
|     {false, false, "1,1"}
 | |
| };
 | |
| 
 | |
| TEST_P(MatcherTest, MatchResult) {
 | |
|   const MatchParam &Param = GetParam();
 | |
|  
 | |
|   EXPECT_TRUE(matchText(Param.Text, Param.AllowComma) == Param.Matched);
 | |
| }
 | |
| 
 | |
| INSTANTIATE_TEST_SUITE_P(IntegralLiteralExpressionMatcherTests, MatcherTest,
 | |
|                          ::testing::ValuesIn(MatchParams));
 | |
| 
 | |
| static const SizeParam SizeParams[] = {
 | |
|     {modernize::LiteralSize::Int, "1"},
 | |
|     {modernize::LiteralSize::UnsignedInt, "1U"},
 | |
|     {modernize::LiteralSize::Long, "1L"},
 | |
|     {modernize::LiteralSize::UnsignedLong, "1UL"},
 | |
|     {modernize::LiteralSize::UnsignedLong, "1LU"},
 | |
|     {modernize::LiteralSize::LongLong, "1LL"},
 | |
|     {modernize::LiteralSize::UnsignedLongLong, "1ULL"},
 | |
|     {modernize::LiteralSize::UnsignedLongLong, "1LLU"}};
 | |
| 
 | |
| TEST_P(SizeTest, TokenSize) {
 | |
|   EXPECT_EQ(sizeText(GetParam().Text), GetParam().Size);
 | |
| }
 | |
| 
 | |
| INSTANTIATE_TEST_SUITE_P(IntegralLiteralExpressionMatcherTests, SizeTest,
 | |
|                          ::testing::ValuesIn(SizeParams));
 | |
| 
 | |
| } // namespace test
 | |
| } // namespace tidy
 | |
| } // namespace clang
 |