Parser; simplify (break out) init expression from if/switch/range-for

This commit is contained in:
Daniel Marjamäki 2021-04-25 14:37:27 +02:00
parent dcc90c6dfa
commit 28a7bb63ec
3 changed files with 98 additions and 8 deletions

View File

@ -5143,6 +5143,8 @@ bool Tokenizer::simplifyTokenList1(const char FileName[])
elseif();
simplifyIfSwitchForInit();
simplifyOverloadedOperators();
validate();
@ -8593,6 +8595,66 @@ void Tokenizer::elseif()
}
void Tokenizer::simplifyIfSwitchForInit()
{
if (!isCPP() || mSettings->standards.cpp < Standards::CPP17)
return;
const bool forInit = (mSettings->standards.cpp >= Standards::CPP20);
for (Token *tok = list.front(); tok; tok = tok->next()) {
if (!Token::Match(tok, "if|switch|for ("))
continue;
Token *semicolon = tok->tokAt(2);
while (!Token::Match(semicolon, "[;)]")) {
if (semicolon->str() == "(")
semicolon = semicolon->link();
semicolon = semicolon->next();
}
if (semicolon->str() != ";")
continue;
if (tok->str() == "for") {
if (!forInit)
continue;
// Is it a for range..
const Token *tok2 = semicolon->next();
bool rangeFor = false;
while (!Token::Match(tok2, "[;)]")) {
if (tok2->str() == "(")
tok2 = tok2->link();
else if (!rangeFor && tok2->str() == "?")
break;
else if (tok2->str() == ":")
rangeFor = true;
tok2 = tok2->next();
}
if (!rangeFor || tok2->str() != ")")
continue;
}
Token *endpar = tok->linkAt(1);
if (!Token::simpleMatch(endpar, ") {"))
continue;
Token *endscope = endpar->linkAt(1);
if (Token::simpleMatch(endscope, "} else {"))
endscope = endscope->linkAt(2);
// Simplify, the initialization expression is broken out..
semicolon->insertToken(tok->str());
semicolon->next()->insertToken("(");
Token::createMutualLinks(semicolon->next()->next(), endpar);
tok->deleteNext();
tok->str("{");
endscope->insertToken("}");
Token::createMutualLinks(tok, endscope->next());
}
}
bool Tokenizer::simplifyRedundantParentheses()
{
bool ret = false;

View File

@ -449,6 +449,9 @@ public:
/** Simplify "if else" */
void elseif();
/** Simplify C++17/C++20 if/switch/for initialization expression */
void simplifyIfSwitchForInit();
/** Simplify conditions
* @return true if something is modified
* false if nothing is done.

View File

@ -281,7 +281,6 @@ private:
TEST_CASE(bitfields14); // ticket #4561 (segfault for 'class a { signals: };')
TEST_CASE(bitfields15); // ticket #7747 (enum Foo {A,B}:4;)
TEST_CASE(bitfields16); // Save bitfield bit count
TEST_CASE(bitfields17); // for (A; b:c);
TEST_CASE(simplifyNamespaceStd);
@ -422,6 +421,11 @@ private:
TEST_CASE(simplifyCoroutines);
TEST_CASE(simplifySpaceshipOperator);
TEST_CASE(simplifyIfSwitchForInit1);
TEST_CASE(simplifyIfSwitchForInit2);
TEST_CASE(simplifyIfSwitchForInit3);
TEST_CASE(simplifyIfSwitchForInit4);
}
std::string tokenizeAndStringify(const char code[], bool expand = true, Settings::PlatformType platform = Settings::Native, const char* filename = "test.cpp", bool cpp11 = true) {
@ -3953,13 +3957,6 @@ private:
ASSERT_EQUALS(1, x->bits());
}
void bitfields17() {
Settings settings;
settings.standards.cpp = Standards::CPP20;
const char code[] = "void f() { for (a;b:c) {} }";
ASSERT_EQUALS("void f ( ) { for ( a ; b : c ) { } }", tokenizeAndStringify(code, settings));
}
void simplifyNamespaceStd() {
const char *code, *expected;
@ -6556,6 +6553,34 @@ private:
ASSERT_EQUALS("; x <=> y ;", tokenizeAndStringify(";x<=>y;", settings));
}
void simplifyIfSwitchForInit1() {
Settings settings;
settings.standards.cpp = Standards::CPP17;
const char code[] = "void f() { if (a;b) {} }";
ASSERT_EQUALS("void f ( ) { { a ; if ( b ) { } } }", tokenizeAndStringify(code, settings));
}
void simplifyIfSwitchForInit2() {
Settings settings;
settings.standards.cpp = Standards::CPP20;
const char code[] = "void f() { if (a;b) {} else {} }";
ASSERT_EQUALS("void f ( ) { { a ; if ( b ) { } else { } } }", tokenizeAndStringify(code, settings));
}
void simplifyIfSwitchForInit3() {
Settings settings;
settings.standards.cpp = Standards::CPP20;
const char code[] = "void f() { switch (a;b) {} }";
ASSERT_EQUALS("void f ( ) { { a ; switch ( b ) { } } }", tokenizeAndStringify(code, settings));
}
void simplifyIfSwitchForInit4() {
Settings settings;
settings.standards.cpp = Standards::CPP20;
const char code[] = "void f() { for (a;b:c) {} }";
ASSERT_EQUALS("void f ( ) { { a ; for ( b : c ) { } } }", tokenizeAndStringify(code, settings));
}
};
REGISTER_TEST(TestTokenizer)