Tokenizer: Cleanup stuff in simplifyTokenList2
This commit is contained in:
parent
63e567eb50
commit
d204c5f894
293
lib/tokenize.cpp
293
lib/tokenize.cpp
|
@ -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);
|
||||||
|
|
|
@ -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();
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue