Tokenizer::simplifyKnownVariables: Broke out the simplification into a separate function

This commit is contained in:
Daniel Marjamäki 2011-02-11 20:12:51 +01:00
parent eddbfbee1e
commit 951a81d0d2
2 changed files with 407 additions and 393 deletions

View File

@ -6297,399 +6297,7 @@ bool Tokenizer::simplifyKnownVariables()
tok3 = tok2->next();
}
Token* bailOutFromLoop = 0;
int indentlevel3 = indentlevel; // indentlevel for tok3
bool ret3 = false;
for (; tok3; tok3 = tok3->next())
{
if (tok3->str() == "{")
{
++indentlevel3;
}
else if (tok3->str() == "}")
{
--indentlevel3;
if (indentlevel3 < indentlevel)
{
if (Token::Match(tok2->tokAt(-7), "%type% * %var% ; %var% = & %var% ;") &&
tok2->tokAt(-5)->str() == tok2->tokAt(-3)->str())
{
tok2 = tok2->tokAt(-4);
Token::eraseTokens(tok2, tok2->tokAt(5));
}
break;
}
}
// Stop if label is found
if (Token::Match(tok3, "; %type% : ;"))
break;
// Stop if return or break is found ..
if (tok3->str() == "break")
break;
if ((indentlevel3 > 1 || !Token::simpleMatch(Token::findmatch(tok3,";"), "; }")) && tok3->str() == "return")
ret3 = true;
if (ret3 && tok3->str() == ";")
break;
if (pointeralias && Token::Match(tok3, ("!!= " + value).c_str()))
break;
// Stop if do is found
if (tok3->str() == "do")
break;
// Stop if something like 'while (--var)' is found
if (tok3->str() == "for" || tok3->str() == "while" || tok3->str() == "do")
{
const Token *endpar = tok3->next()->link();
if (Token::simpleMatch(endpar, ") {"))
endpar = endpar->next()->link();
bool bailout = false;
for (const Token *tok4 = tok3; tok4 && tok4 != endpar; tok4 = tok4->next())
{
if (Token::Match(tok4, "++|-- %varid%", varid) ||
Token::Match(tok4, "%varid% ++|--|=", varid))
{
bailout = true;
break;
}
}
if (bailout)
break;
}
if (bailOutFromLoop)
{
// This could be a loop, skip it, but only if it doesn't contain
// the variable we are checking for. If it contains the variable
// we will bail out.
if (tok3->varId() == varid)
{
// Continue
//tok2 = bailOutFromLoop;
break;
}
else if (tok3 == bailOutFromLoop)
{
// We have skipped the loop
bailOutFromLoop = 0;
continue;
}
continue;
}
else if (tok3->str() == "{" && tok3->previous()->str() == ")")
{
// There is a possible loop after the assignment. Try to skip it.
if (tok3->previous()->link() &&
!Token::simpleMatch(tok3->previous()->link()->previous(), "if"))
bailOutFromLoop = tok3->link();
continue;
}
// Variable used in realloc (see Ticket #1649)
if (Token::Match(tok3, "%var% = realloc ( %var% ,") &&
tok3->varId() == varid &&
tok3->tokAt(4)->varId() == varid)
{
tok3->tokAt(4)->str(value);
ret = true;
}
// condition "(|&&|%OROR% %varid% )|&&|%OROR%
if (!Token::Match(tok3->previous(), "( %var% )") &&
(Token::Match(tok3->previous(), "&&|(") || tok3->strAt(-1) == "||") &&
tok3->varId() == varid &&
(Token::Match(tok3->next(), "&&|)") || tok3->strAt(1) == "||"))
{
tok3->str(value);
ret = true;
}
// Variable is used somehow in a non-defined pattern => bail out
if (tok3->varId() == varid)
{
// This is a really generic bailout so let's try to avoid this.
// There might be lots of false negatives.
if (_settings->debugwarnings)
{
// FIXME: Fix all the debug warnings for values and then
// remove this bailout
if (pointeralias)
break;
// suppress debug-warning when calling member function
if (Token::Match(tok3->next(), ". %var% ("))
break;
// suppress debug-warning when assignment
if (Token::simpleMatch(tok3->next(), "="))
break;
// taking address of variable..
if (Token::Match(tok3->tokAt(-2), "return|= & %var% ;"))
break;
// parameter in function call..
if (Token::Match(tok3->tokAt(-2), "%var% ( %var% ,|)") ||
Token::Match(tok3->previous(), ", %var% ,|)"))
break;
// conditional increment
if (Token::Match(tok3->tokAt(-3), ") { ++|--") ||
Token::Match(tok3->tokAt(-2), ") { %var% ++|--"))
break;
std::list<ErrorLogger::ErrorMessage::FileLocation> locationList;
ErrorLogger::ErrorMessage::FileLocation loc;
loc.line = tok3->linenr();
loc.setfile(file(tok3));
locationList.push_back(loc);
const ErrorLogger::ErrorMessage errmsg(locationList,
Severity::debug,
"simplifyKnownVariables: bailing out (variable="+tok3->str()+", value="+value+")",
"debug");
if (_errorLogger)
_errorLogger->reportErr(errmsg);
else
Check::reportError(errmsg);
}
break;
}
// Using the variable in condition..
if (Token::Match(tok3->previous(), ("if ( " + structname + " %varid% ==|!=|<|<=|>|>=|)").c_str(), varid) ||
Token::Match(tok3, ("( " + structname + " %varid% ==|!=|<|<=|>|>=").c_str(), varid) ||
Token::Match(tok3, ("!|==|!=|<|<=|>|>= " + structname + " %varid% ==|!=|<|<=|>|>=|)").c_str(), varid) ||
Token::Match(tok3->previous(), "strlen|free ( %varid% )", varid))
{
if (!structname.empty())
{
tok3->deleteNext();
tok3->deleteNext();
}
tok3 = tok3->next();
tok3->str(value);
tok3->varId(valueVarId);
ret = true;
}
// Delete pointer alias
if (pointeralias && tok3->str() == "delete" &&
(Token::Match(tok3, "delete %varid% ;", varid) ||
Token::Match(tok3, "delete [ ] %varid%", varid)))
{
tok3 = (tok3->strAt(1) == "[") ? tok3->tokAt(3) : tok3->next();
tok3->str(value);
tok3->varId(valueVarId);
ret = true;
}
// Variable is used in function call..
if (Token::Match(tok3, ("%var% ( " + structname + " %varid% ,").c_str(), varid))
{
const char * const functionName[] =
{
"memcmp","memcpy","memmove","memset",
"strcmp","strcpy","strncpy","strdup"
};
for (unsigned int i = 0; i < (sizeof(functionName) / sizeof(*functionName)); ++i)
{
if (tok3->str() == functionName[i])
{
Token *par1 = tok3->next()->next();
if (!structname.empty())
{
par1->deleteThis();
par1->deleteThis();
}
par1->str(value);
par1->varId(valueVarId);
break;
}
}
}
// Variable is used as 2nd parameter in function call..
if (Token::Match(tok3, ("%var% ( %any% , " + structname + " %varid% ,|)").c_str(), varid))
{
const char * const functionName[] =
{
"memcmp","memcpy","memmove",
"strcmp","strcpy","strncmp","strncpy"
};
for (unsigned int i = 0; i < (sizeof(functionName) / sizeof(*functionName)); ++i)
{
if (tok3->str() == functionName[i])
{
Token *par = tok3->tokAt(4);
if (!structname.empty())
{
par->deleteThis();
par->deleteThis();
}
par->str(value);
par->varId(valueVarId);
break;
}
}
}
// array usage
if (Token::Match(tok3, ("[(,] " + structname + " %varid% [+-*/[]").c_str(), varid))
{
if (!structname.empty())
{
tok3->deleteNext();
tok3->deleteNext();
}
tok3 = tok3->next();
tok3->str(value);
tok3->varId(valueVarId);
ret = true;
}
// Variable is used in calculation..
if (((tok3->previous()->varId() > 0) && Token::Match(tok3, ("& " + structname + " %varid%").c_str(), varid)) ||
Token::Match(tok3, ("[=+-*/[] " + structname + " %varid% [=?+-*/;])]").c_str(), varid) ||
Token::Match(tok3, ("[(=+-*/[] " + structname + " %varid% <<|>>").c_str(), varid) ||
Token::Match(tok3, ("<<|>> " + structname + " %varid% [+-*/;])]").c_str(), varid) ||
Token::Match(tok3->previous(), ("[=+-*/[] ( " + structname + " %varid%").c_str(), varid))
{
if (!structname.empty())
{
tok3->deleteNext();
tok3->deleteNext();
}
tok3 = tok3->next();
tok3->str(value);
tok3->varId(valueVarId);
if (tok3->previous()->str() == "*" && valueIsPointer)
{
tok3 = tok3->previous();
tok3->deleteThis();
}
ret = true;
}
if (Token::simpleMatch(tok3, "= {"))
{
unsigned int indentlevel4 = 0;
for (const Token *tok4 = tok3; tok4; tok4 = tok4->next())
{
if (tok4->str() == "{")
++indentlevel4;
else if (tok4->str() == "}")
{
if (indentlevel4 <= 1)
break;
--indentlevel4;
}
if (Token::Match(tok4, "{|, %varid% ,|}", varid))
{
tok4->next()->str(value);
tok4->next()->varId(valueVarId);
ret = true;
}
}
}
// Using the variable in for-condition..
if (Token::simpleMatch(tok3, "for ("))
{
for (Token *tok4 = tok3->tokAt(2); tok4; tok4 = tok4->next())
{
if (tok4->str() == "(" || tok4->str() == ")")
break;
// Replace variable used in condition..
if (Token::Match(tok4, "; %var% <|<=|!= %var% ; ++| %var% ++| )"))
{
const Token *inctok = tok4->tokAt(5);
if (inctok->str() == "++")
inctok = inctok->next();
if (inctok->varId() == varid)
break;
if (tok4->next()->varId() == varid)
{
tok4->next()->str(value);
tok4->next()->varId(valueVarId);
ret = true;
}
if (tok4->tokAt(3)->varId() == varid)
{
tok4->tokAt(3)->str(value);
tok4->tokAt(3)->varId(valueVarId);
ret = true;
}
}
}
}
if (indentlevel == indentlevel3 && Token::Match(tok3->next(), "%varid% ++|--", varid) && MathLib::isInt(value))
{
const std::string op(tok3->strAt(2));
if (Token::Match(tok3, "[{};] %any% %any% ;"))
{
Token::eraseTokens(tok3, tok3->tokAt(3));
}
else
{
tok3 = tok3->next();
tok3->str(value);
tok3->varId(valueVarId);
tok3->deleteNext();
}
incdec(value, op);
if (!Token::simpleMatch(tok2->tokAt(-2), "for ("))
{
tok2->tokAt(2)->str(value);
tok2->tokAt(2)->varId(valueVarId);
}
ret = true;
}
if (indentlevel == indentlevel3 && Token::Match(tok3->next(), "++|-- %varid%", varid) && MathLib::isInt(value) &&
!Token::Match(tok3->tokAt(3), "[.[]"))
{
incdec(value, tok3->strAt(1));
tok2->tokAt(2)->str(value);
tok2->tokAt(2)->varId(valueVarId);
if (Token::Match(tok3, "[;{}] %any% %any% ;"))
{
Token::eraseTokens(tok3, tok3->tokAt(3));
}
else
{
tok3->deleteNext();
tok3->next()->str(value);
tok3->next()->varId(valueVarId);
}
tok3 = tok3->next();
ret = true;
}
// return variable..
if (Token::Match(tok3, "return %varid% %any%", varid) &&
isOp(tok3->tokAt(2)))
{
tok3->next()->str(value);
tok3->next()->varId(valueVarId);
}
else if (pointeralias && Token::Match(tok3, "return * %varid% ;", varid))
{
tok3->deleteNext();
tok3->next()->str(value);
tok3->next()->varId(valueVarId);
}
}
ret |= simplifyKnownVariablesSimplify(&tok2, tok3, varid, structname, value, valueVarId, valueIsPointer, pointeralias, indentlevel);
}
}
@ -6700,6 +6308,406 @@ bool Tokenizer::simplifyKnownVariables()
return ret;
}
bool Tokenizer::simplifyKnownVariablesSimplify(Token **tok2, Token *tok3, unsigned int varid, const std::string &structname, std::string &value, unsigned int valueVarId, bool valueIsPointer, bool pointeralias, int indentlevel)
{
bool ret = false;;
Token* bailOutFromLoop = 0;
int indentlevel3 = indentlevel;
bool ret3 = false;
for (; tok3; tok3 = tok3->next())
{
if (tok3->str() == "{")
{
++indentlevel3;
}
else if (tok3->str() == "}")
{
--indentlevel3;
if (indentlevel3 < indentlevel)
{
if (Token::Match((*tok2)->tokAt(-7), "%type% * %var% ; %var% = & %var% ;") &&
(*tok2)->tokAt(-5)->str() == (*tok2)->tokAt(-3)->str())
{
(*tok2) = (*tok2)->tokAt(-4);
Token::eraseTokens((*tok2), (*tok2)->tokAt(5));
}
break;
}
}
// Stop if label is found
if (Token::Match(tok3, "; %type% : ;"))
break;
// Stop if return or break is found ..
if (tok3->str() == "break")
break;
if ((indentlevel3 > 1 || !Token::simpleMatch(Token::findmatch(tok3,";"), "; }")) && tok3->str() == "return")
ret3 = true;
if (ret3 && tok3->str() == ";")
break;
if (pointeralias && Token::Match(tok3, ("!!= " + value).c_str()))
break;
// Stop if do is found
if (tok3->str() == "do")
break;
// Stop if something like 'while (--var)' is found
if (tok3->str() == "for" || tok3->str() == "while" || tok3->str() == "do")
{
const Token *endpar = tok3->next()->link();
if (Token::simpleMatch(endpar, ") {"))
endpar = endpar->next()->link();
bool bailout = false;
for (const Token *tok4 = tok3; tok4 && tok4 != endpar; tok4 = tok4->next())
{
if (Token::Match(tok4, "++|-- %varid%", varid) ||
Token::Match(tok4, "%varid% ++|--|=", varid))
{
bailout = true;
break;
}
}
if (bailout)
break;
}
if (bailOutFromLoop)
{
// This could be a loop, skip it, but only if it doesn't contain
// the variable we are checking for. If it contains the variable
// we will bail out.
if (tok3->varId() == varid)
{
// Continue
//tok2 = bailOutFromLoop;
break;
}
else if (tok3 == bailOutFromLoop)
{
// We have skipped the loop
bailOutFromLoop = 0;
continue;
}
continue;
}
else if (tok3->str() == "{" && tok3->previous()->str() == ")")
{
// There is a possible loop after the assignment. Try to skip it.
if (tok3->previous()->link() &&
!Token::simpleMatch(tok3->previous()->link()->previous(), "if"))
bailOutFromLoop = tok3->link();
continue;
}
// Variable used in realloc (see Ticket #1649)
if (Token::Match(tok3, "%var% = realloc ( %var% ,") &&
tok3->varId() == varid &&
tok3->tokAt(4)->varId() == varid)
{
tok3->tokAt(4)->str(value);
ret = true;
}
// condition "(|&&|%OROR% %varid% )|&&|%OROR%
if (!Token::Match(tok3->previous(), "( %var% )") &&
(Token::Match(tok3->previous(), "&&|(") || tok3->strAt(-1) == "||") &&
tok3->varId() == varid &&
(Token::Match(tok3->next(), "&&|)") || tok3->strAt(1) == "||"))
{
tok3->str(value);
ret = true;
}
// Variable is used somehow in a non-defined pattern => bail out
if (tok3->varId() == varid)
{
// This is a really generic bailout so let's try to avoid this.
// There might be lots of false negatives.
if (_settings->debugwarnings)
{
// FIXME: Fix all the debug warnings for values and then
// remove this bailout
if (pointeralias)
break;
// suppress debug-warning when calling member function
if (Token::Match(tok3->next(), ". %var% ("))
break;
// suppress debug-warning when assignment
if (Token::simpleMatch(tok3->next(), "="))
break;
// taking address of variable..
if (Token::Match(tok3->tokAt(-2), "return|= & %var% ;"))
break;
// parameter in function call..
if (Token::Match(tok3->tokAt(-2), "%var% ( %var% ,|)") ||
Token::Match(tok3->previous(), ", %var% ,|)"))
break;
// conditional increment
if (Token::Match(tok3->tokAt(-3), ") { ++|--") ||
Token::Match(tok3->tokAt(-2), ") { %var% ++|--"))
break;
std::list<ErrorLogger::ErrorMessage::FileLocation> locationList;
ErrorLogger::ErrorMessage::FileLocation loc;
loc.line = tok3->linenr();
loc.setfile(file(tok3));
locationList.push_back(loc);
const ErrorLogger::ErrorMessage errmsg(locationList,
Severity::debug,
"simplifyKnownVariables: bailing out (variable="+tok3->str()+", value="+value+")",
"debug");
if (_errorLogger)
_errorLogger->reportErr(errmsg);
else
Check::reportError(errmsg);
}
break;
}
// Using the variable in condition..
if (Token::Match(tok3->previous(), ("if ( " + structname + " %varid% ==|!=|<|<=|>|>=|)").c_str(), varid) ||
Token::Match(tok3, ("( " + structname + " %varid% ==|!=|<|<=|>|>=").c_str(), varid) ||
Token::Match(tok3, ("!|==|!=|<|<=|>|>= " + structname + " %varid% ==|!=|<|<=|>|>=|)").c_str(), varid) ||
Token::Match(tok3->previous(), "strlen|free ( %varid% )", varid))
{
if (!structname.empty())
{
tok3->deleteNext();
tok3->deleteNext();
}
tok3 = tok3->next();
tok3->str(value);
tok3->varId(valueVarId);
ret = true;
}
// Delete pointer alias
if (pointeralias && tok3->str() == "delete" &&
(Token::Match(tok3, "delete %varid% ;", varid) ||
Token::Match(tok3, "delete [ ] %varid%", varid)))
{
tok3 = (tok3->strAt(1) == "[") ? tok3->tokAt(3) : tok3->next();
tok3->str(value);
tok3->varId(valueVarId);
ret = true;
}
// Variable is used in function call..
if (Token::Match(tok3, ("%var% ( " + structname + " %varid% ,").c_str(), varid))
{
const char * const functionName[] =
{
"memcmp","memcpy","memmove","memset",
"strcmp","strcpy","strncpy","strdup"
};
for (unsigned int i = 0; i < (sizeof(functionName) / sizeof(*functionName)); ++i)
{
if (tok3->str() == functionName[i])
{
Token *par1 = tok3->next()->next();
if (!structname.empty())
{
par1->deleteThis();
par1->deleteThis();
}
par1->str(value);
par1->varId(valueVarId);
break;
}
}
}
// Variable is used as 2nd parameter in function call..
if (Token::Match(tok3, ("%var% ( %any% , " + structname + " %varid% ,|)").c_str(), varid))
{
const char * const functionName[] =
{
"memcmp","memcpy","memmove",
"strcmp","strcpy","strncmp","strncpy"
};
for (unsigned int i = 0; i < (sizeof(functionName) / sizeof(*functionName)); ++i)
{
if (tok3->str() == functionName[i])
{
Token *par = tok3->tokAt(4);
if (!structname.empty())
{
par->deleteThis();
par->deleteThis();
}
par->str(value);
par->varId(valueVarId);
break;
}
}
}
// array usage
if (Token::Match(tok3, ("[(,] " + structname + " %varid% [+-*/[]").c_str(), varid))
{
if (!structname.empty())
{
tok3->deleteNext();
tok3->deleteNext();
}
tok3 = tok3->next();
tok3->str(value);
tok3->varId(valueVarId);
ret = true;
}
// Variable is used in calculation..
if (((tok3->previous()->varId() > 0) && Token::Match(tok3, ("& " + structname + " %varid%").c_str(), varid)) ||
Token::Match(tok3, ("[=+-*/[] " + structname + " %varid% [=?+-*/;])]").c_str(), varid) ||
Token::Match(tok3, ("[(=+-*/[] " + structname + " %varid% <<|>>").c_str(), varid) ||
Token::Match(tok3, ("<<|>> " + structname + " %varid% [+-*/;])]").c_str(), varid) ||
Token::Match(tok3->previous(), ("[=+-*/[] ( " + structname + " %varid%").c_str(), varid))
{
if (!structname.empty())
{
tok3->deleteNext();
tok3->deleteNext();
}
tok3 = tok3->next();
tok3->str(value);
tok3->varId(valueVarId);
if (tok3->previous()->str() == "*" && valueIsPointer)
{
tok3 = tok3->previous();
tok3->deleteThis();
}
ret = true;
}
if (Token::simpleMatch(tok3, "= {"))
{
unsigned int indentlevel4 = 0;
for (const Token *tok4 = tok3; tok4; tok4 = tok4->next())
{
if (tok4->str() == "{")
++indentlevel4;
else if (tok4->str() == "}")
{
if (indentlevel4 <= 1)
break;
--indentlevel4;
}
if (Token::Match(tok4, "{|, %varid% ,|}", varid))
{
tok4->next()->str(value);
tok4->next()->varId(valueVarId);
ret = true;
}
}
}
// Using the variable in for-condition..
if (Token::simpleMatch(tok3, "for ("))
{
for (Token *tok4 = tok3->tokAt(2); tok4; tok4 = tok4->next())
{
if (tok4->str() == "(" || tok4->str() == ")")
break;
// Replace variable used in condition..
if (Token::Match(tok4, "; %var% <|<=|!= %var% ; ++| %var% ++| )"))
{
const Token *inctok = tok4->tokAt(5);
if (inctok->str() == "++")
inctok = inctok->next();
if (inctok->varId() == varid)
break;
if (tok4->next()->varId() == varid)
{
tok4->next()->str(value);
tok4->next()->varId(valueVarId);
ret = true;
}
if (tok4->tokAt(3)->varId() == varid)
{
tok4->tokAt(3)->str(value);
tok4->tokAt(3)->varId(valueVarId);
ret = true;
}
}
}
}
if (indentlevel == indentlevel3 && Token::Match(tok3->next(), "%varid% ++|--", varid) && MathLib::isInt(value))
{
const std::string op(tok3->strAt(2));
if (Token::Match(tok3, "[{};] %any% %any% ;"))
{
Token::eraseTokens(tok3, tok3->tokAt(3));
}
else
{
tok3 = tok3->next();
tok3->str(value);
tok3->varId(valueVarId);
tok3->deleteNext();
}
incdec(value, op);
if (!Token::simpleMatch((*tok2)->tokAt(-2), "for ("))
{
(*tok2)->tokAt(2)->str(value);
(*tok2)->tokAt(2)->varId(valueVarId);
}
ret = true;
}
if (indentlevel == indentlevel3 && Token::Match(tok3->next(), "++|-- %varid%", varid) && MathLib::isInt(value) &&
!Token::Match(tok3->tokAt(3), "[.[]"))
{
incdec(value, tok3->strAt(1));
(*tok2)->tokAt(2)->str(value);
(*tok2)->tokAt(2)->varId(valueVarId);
if (Token::Match(tok3, "[;{}] %any% %any% ;"))
{
Token::eraseTokens(tok3, tok3->tokAt(3));
}
else
{
tok3->deleteNext();
tok3->next()->str(value);
tok3->next()->varId(valueVarId);
}
tok3 = tok3->next();
ret = true;
}
// return variable..
if (Token::Match(tok3, "return %varid% %any%", varid) &&
isOp(tok3->tokAt(2)))
{
tok3->next()->str(value);
tok3->next()->varId(valueVarId);
}
else if (pointeralias && Token::Match(tok3, "return * %varid% ;", varid))
{
tok3->deleteNext();
tok3->next()->str(value);
tok3->next()->varId(valueVarId);
}
}
return ret;
}
void Tokenizer::elseif()
{

View File

@ -308,6 +308,12 @@ public:
*/
bool simplifyKnownVariables();
/**
* utility function for simplifyKnownVariables. Perform simplification
* of a given variable
*/
bool simplifyKnownVariablesSimplify(Token **tok2, Token *tok3, unsigned int varid, const std::string &structname, std::string &value, unsigned int valueVarId, bool valueIsPointer, bool pointeralias, int indentlevel);
/** Replace a "goto" with the statements */
void simplifyGoto();