Tokenizer: Cleanup stuff in simplifyTokenList2

This commit is contained in:
Daniel Marjamäki 2022-06-25 17:09:51 +02:00
parent 63e567eb50
commit d204c5f894
2 changed files with 0 additions and 315 deletions

View File

@ -5187,33 +5187,6 @@ bool Tokenizer::simplifyTokenList2()
removeRedundantSemicolons(); removeRedundantSemicolons();
simplifyFlowControl();
simplifyRedundantConsecutiveBraces();
simplifyEmptyNamespaces();
validate();
Token::assignProgressValues(list.front());
list.front()->assignIndexes();
list.createAst();
// needed for #7208 (garbage code) and #7724 (ast max depth limit)
list.validateAst();
// Create symbol database and then remove const keywords
createSymbolDatabase();
mSymbolDatabase->setValueTypeInTokenList(true);
ValueFlow::setValues(&list, mSymbolDatabase, mErrorLogger, mSettings);
if (Settings::terminated())
return false;
printDebugOutput(2);
return true; return true;
} }
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
@ -5766,82 +5739,6 @@ void Tokenizer::simplifyEmptyNamespaces()
} }
} }
void Tokenizer::simplifyFlowControl()
{
for (Token *begin = list.front(); begin; begin = begin->next()) {
if (Token::Match(begin, "(|[") ||
(begin->str() == "{" && begin->previous() && begin->strAt(-1) == "="))
begin = begin->link();
//function scope
if (!Token::simpleMatch(begin, ") {") && !Token::Match(begin, ") %name% {"))
continue;
Token* end = begin->linkAt(1+(begin->next()->str() == "{" ? 0 : 1));
int indentLevel = 0;
bool stilldead = false;
for (Token *tok = begin; tok && tok != end; tok = tok->next()) {
if (Token::Match(tok, "(|[")) {
tok = tok->link();
continue;
}
if (tok->str() == "{") {
if (tok->previous() && tok->previous()->str() == "=") {
tok = tok->link();
continue;
}
++indentLevel;
} else if (tok->str() == "}") {
if (indentLevel == 0)
break;
--indentLevel;
if (stilldead) {
eraseDeadCode(tok, nullptr);
if (indentLevel == 1 || tok->next()->str() != "}" || !Token::Match(tok->next()->link()->previous(), ";|{|}|do {"))
stilldead = false;
continue;
}
}
if (indentLevel == 0)
continue;
if (Token::Match(tok,"continue|break ;")) {
tok = tok->next();
eraseDeadCode(tok, nullptr);
} else if (Token::Match(tok,"return|goto") ||
(Token::Match(tok->previous(), "[;{}] %name% (") &&
mSettings->library.isnoreturn(tok)) ||
(isCPP() && tok->str() == "throw")) {
if (tok->next()->str() == "}")
syntaxError(tok->next()); // invalid code like in #6731
//TODO: ensure that we exclude user-defined 'exit|abort|throw', except for 'noreturn'
//catch the first ';'
for (Token *tok2 = tok->next(); tok2; tok2 = tok2->next()) {
if (Token::Match(tok2, "(|[")) {
tok2 = tok2->link();
} else if (tok2->str() == ";") {
tok = tok2;
eraseDeadCode(tok, nullptr);
break;
} else if (Token::Match(tok2, "[{}]"))
break;
}
//if everything is removed, then remove also the code after an inferior scope
//only if the actual scope is not special
if (indentLevel > 1 && tok->next()->str() == "}" && Token::Match(tok->next()->link()->previous(), ";|{|}|do {"))
stilldead = true;
}
}
begin = end;
}
}
void Tokenizer::removeRedundantSemicolons() void Tokenizer::removeRedundantSemicolons()
{ {
for (Token *tok = list.front(); tok; tok = tok->next()) { for (Token *tok = list.front(); tok; tok = tok->next()) {
@ -7399,196 +7296,6 @@ bool Tokenizer::isScopeNoReturn(const Token *endScopeToken, bool *unknown) const
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
void Tokenizer::eraseDeadCode(Token *begin, const Token *end)
{
if (!begin)
return;
const bool isgoto = Token::Match(begin->tokAt(-2), "goto %name% ;");
int indentlevel = 1;
int indentcase = 0;
int indentswitch = 0;
int indentlabel = 0;
int roundbraces = 0;
int indentcheck = 0;
std::vector<int> switchindents;
bool checklabel = false;
Token *tok = begin;
Token *tokcheck = nullptr;
while (tok->next() && tok->next() != end) {
if (tok->next()->str() == "(") {
++roundbraces;
tok->deleteNext();
continue;
} else if (tok->next()->str() == ")") {
if (!roundbraces)
break; //too many ending round parentheses
--roundbraces;
tok->deleteNext();
continue;
}
if (roundbraces) {
tok->deleteNext();
continue;
}
if (Token::Match(tok, "[{};] switch (")) {
if (!checklabel) {
if (!indentlabel) {
//remove 'switch ( ... )'
Token::eraseTokens(tok, tok->linkAt(2)->next());
} else {
tok = tok->linkAt(2);
}
if (tok->next()->str() == "{") {
++indentswitch;
indentcase = indentlevel + 1;
switchindents.push_back(indentcase);
}
} else {
tok = tok->linkAt(2);
if (Token::simpleMatch(tok, ") {")) {
++indentswitch;
indentcase = indentlevel + 1;
switchindents.push_back(indentcase);
}
}
} else if (tok->next()->str() == "{") {
++indentlevel;
if (!checklabel) {
checklabel = true;
tokcheck = tok;
indentcheck = indentlevel;
indentlabel = 0;
}
tok = tok->next();
} else if (tok->next()->str() == "}") {
--indentlevel;
if (!indentlevel)
break;
if (!checklabel) {
tok->deleteNext();
} else {
if (indentswitch && indentlevel == indentcase)
--indentlevel;
if (indentlevel < indentcheck) {
const Token *end2 = tok->next();
tok = end2->link()->previous(); //return to initial '{'
if (indentswitch && Token::simpleMatch(tok, ") {") && Token::Match(tok->link()->tokAt(-2), "[{};] switch ("))
tok = tok->link()->tokAt(-2); //remove also 'switch ( ... )'
Token::eraseTokens(tok, end2->next());
checklabel = false;
tokcheck = nullptr;
indentcheck = 0;
} else {
tok = tok->next();
}
}
if (indentswitch && indentlevel <= indentcase) {
--indentswitch;
switchindents.pop_back();
if (!indentswitch)
indentcase = 0;
else
indentcase = switchindents[indentswitch-1];
}
} else if (Token::Match(tok, "[{};:] case")) {
const Token *tok2 = Token::findsimplematch(tok->next(), ": ;", end);
if (!tok2) {
tok->deleteNext();
continue;
}
if (indentlevel == 1)
break; //it seems like the function was called inside a case-default block.
if (indentlevel == indentcase)
++indentlevel;
tok2 = tok2->next();
if (!checklabel || !indentswitch) {
Token::eraseTokens(tok, tok2->next());
} else {
tok = const_cast<Token *>(tok2);
}
} else if (Token::Match(tok, "[{};] default : ;")) {
if (indentlevel == 1)
break; //it seems like the function was called inside a case-default block.
if (indentlevel == indentcase)
++indentlevel;
if (!checklabel || !indentswitch) {
tok->deleteNext(3);
} else {
tok = tok->tokAt(3);
}
} else if (Token::Match(tok, "[{};] %name% : ;") && tok->next()->str() != "default") {
if (checklabel) {
indentlabel = indentlevel;
tok = tokcheck->next();
checklabel = false;
indentlevel = indentcheck;
} else {
if (indentswitch) {
//Before stopping the function, since the 'switch()'
//instruction is removed, there's no sense to keep the
//case instructions. Remove them, if there are any.
Token *tok2 = tok->tokAt(3);
int indentlevel2 = indentlevel;
while (tok2->next() && tok2->next() != end) {
if (Token::Match(tok2->next(), "{|[|(")) {
tok2 = tok2->next()->link();
} else if (Token::Match(tok2, "[{};:] case")) {
const Token *tok3 = Token::findsimplematch(tok2->next(), ": ;", end);
if (!tok3) {
tok2 = tok2->next();
continue;
}
Token::eraseTokens(tok2, tok3->next());
} else if (Token::Match(tok2, "[{};] default : ;")) {
tok2->deleteNext(3);
} else if (tok2->next()->str() == "}") {
--indentlevel2;
if (indentlevel2 <= indentcase)
break;
tok2 = tok2->next();
} else {
tok2 = tok2->next();
}
}
}
break; //stop removing tokens, we arrived to the label.
}
} else if (isgoto && Token::Match(tok, "[{};] do|while|for|BOOST_FOREACH")) {
//it's possible that code inside loop is not dead,
//because of the possible presence of the label pointed by 'goto'
const Token *start = tok->tokAt(2);
if (start && start->str() == "(")
start = start->link()->next();
if (start && start->str() == "{") {
std::string labelpattern = "[{};] " + begin->previous()->str() + " : ;";
bool simplify = true;
for (Token *tok2 = start->next(); tok2 != start->link(); tok2 = tok2->next()) {
if (Token::Match(tok2, labelpattern.c_str())) {
simplify = false;
break;
}
}
//bailout for now
if (!simplify)
break;
}
tok->deleteNext();
} else {
// no need to keep the other strings, remove them.
if (tok->strAt(1) == "while") {
if (tok->str() == "}" && tok->link()->strAt(-1) == "do")
tok->link()->previous()->deleteThis();
}
tok->deleteNext();
}
}
}
//---------------------------------------------------------------------------
void Tokenizer::syntaxError(const Token *tok, const std::string &code) const void Tokenizer::syntaxError(const Token *tok, const std::string &code) const
{ {
printDebugOutput(0); printDebugOutput(0);

View File

@ -159,23 +159,6 @@ public:
void splitTemplateRightAngleBrackets(bool check); void splitTemplateRightAngleBrackets(bool check);
/**
* Deletes dead code between 'begin' and 'end'.
* In general not everything can be erased, such as:
* - code after labels;
* - code outside the scope where the function is called;
* - code after a change of scope caused by 'switch(...);'
* instructions, like 'case %any%;' or 'default;'
* Also, if the dead code contains a 'switch' block
* and inside it there's a label, the function removes all
* the 'switch(..)' tokens and every occurrence of 'case %any%; | default;'
* expression, such as the 'switch' block is reduced to a simple block.
*
* @param begin Tokens after this have a possibility to be erased.
* @param end Tokens before this have a possibility to be erased.
*/
static void eraseDeadCode(Token *begin, const Token *end);
/** /**
* Calculates sizeof value for given type. * Calculates sizeof value for given type.
* @param type Token which will contain e.g. "int", "*", or string. * @param type Token which will contain e.g. "int", "*", or string.
@ -332,11 +315,6 @@ public:
/** Simplify useless C++ empty namespaces, like: 'namespace %name% { }'*/ /** Simplify useless C++ empty namespaces, like: 'namespace %name% { }'*/
void simplifyEmptyNamespaces(); void simplifyEmptyNamespaces();
/** Simplify redundant code placed after control flow statements :
* 'return', 'throw', 'goto', 'break' and 'continue'
*/
void simplifyFlowControl();
/** Simplify "if else" */ /** Simplify "if else" */
void elseif(); void elseif();