Remove simplifyKnownVariables() (#4232)

* Remove simplifyKnownVariables()

* Add some test cases back

* Remove unused functions

* Format
This commit is contained in:
chrchr-github 2022-06-25 08:38:17 +02:00 committed by GitHub
parent 11860cce4b
commit 63e567eb50
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 50 additions and 1464 deletions

View File

@ -1037,23 +1037,6 @@ std::string MathLib::subtract(const std::string &first, const std::string &secon
#endif #endif
} }
std::string MathLib::incdec(const std::string & var, const std::string & op)
{
#ifdef TEST_MATHLIB_VALUE
if (op == "++")
return value(var).add(1).str();
else if (op == "--")
return value(var).add(-1).str();
#else
if (op == "++")
return MathLib::add(var, "1");
else if (op == "--")
return MathLib::subtract(var, "1");
#endif
throw InternalError(nullptr, std::string("Unexpected operation '") + op + "' in MathLib::incdec(). Please report this to Cppcheck developers.");
}
std::string MathLib::divide(const std::string &first, const std::string &second) std::string MathLib::divide(const std::string &first, const std::string &second)
{ {
#ifdef TEST_MATHLIB_VALUE #ifdef TEST_MATHLIB_VALUE

View File

@ -106,7 +106,6 @@ public:
static std::string multiply(const std::string & first, const std::string & second); static std::string multiply(const std::string & first, const std::string & second);
static std::string divide(const std::string & first, const std::string & second); static std::string divide(const std::string & first, const std::string & second);
static std::string mod(const std::string & first, const std::string & second); static std::string mod(const std::string & first, const std::string & second);
static std::string incdec(const std::string & var, const std::string & op);
static std::string calculate(const std::string & first, const std::string & second, char action); static std::string calculate(const std::string & first, const std::string & second, char action);
static std::string sin(const std::string & tok); static std::string sin(const std::string & tok);

View File

@ -5178,8 +5178,6 @@ bool Tokenizer::simplifyTokenList2()
return false; return false;
modified = false; modified = false;
modified |= simplifyKnownVariables();
modified |= simplifyConstTernaryOp(); modified |= simplifyConstTernaryOp();
modified |= simplifyCalculations(); modified |= simplifyCalculations();
validate(); validate();
@ -7038,767 +7036,6 @@ Token * Tokenizer::initVar(Token * tok)
return tok; return tok;
} }
bool Tokenizer::simplifyKnownVariables()
{
// return value for function. Set to true if any simplifications are made
bool ret = false;
// constants..
{
std::unordered_map<int, std::string> constantValues;
std::map<int, Token*> constantVars;
std::unordered_map<int, std::list<Token*>> constantValueUsages;
for (Token *tok = list.front(); tok; tok = tok->next()) {
// Reference to variable
if (Token::Match(tok, "%type%|* & %name% = %name% ;")) {
Token *start = tok->previous();
while (Token::Match(start,"%type%|*|&"))
start = start->previous();
if (!Token::Match(start,"[;{}]"))
continue;
const Token *reftok = tok->tokAt(2);
const Token *vartok = reftok->tokAt(2);
int level = 0;
for (Token *tok2 = tok->tokAt(6); tok2; tok2 = tok2->next()) {
if (tok2->str() == "{") {
++level;
} else if (tok2->str() == "}") {
if (level <= 0)
break;
--level;
} else if (tok2->varId() == reftok->varId()) {
tok2->str(vartok->str());
tok2->varId(vartok->varId());
}
}
Token::eraseTokens(start, tok->tokAt(6));
tok = start;
}
if (tok->isName() && (Token::Match(tok, "static| const| static| %type% const| %name% = %any% ;") ||
Token::Match(tok, "static| const| static| %type% const| %name% ( %any% ) ;"))) {
bool isconst = false;
for (const Token *tok2 = tok; (tok2->str() != "=") && (tok2->str() != "("); tok2 = tok2->next()) {
if (tok2->str() == "const") {
isconst = true;
break;
}
}
if (!isconst)
continue;
Token *tok1 = tok;
// start of statement
if (tok != list.front() && !Token::Match(tok->previous(),";|{|}|private:|protected:|public:"))
continue;
// skip "const" and "static"
while (Token::Match(tok, "const|static"))
tok = tok->next();
// pod type
if (!tok->isStandardType())
continue;
Token * const vartok = (tok->next() && tok->next()->str() == "const") ? tok->tokAt(2) : tok->next();
const Token * const valuetok = vartok->tokAt(2);
if (Token::Match(valuetok, "%bool%|%char%|%num%|%str% )| ;")) {
// record a constant value for this variable
constantValues[vartok->varId()] = valuetok->str();
constantVars[vartok->varId()] = tok1;
}
} else if (tok->varId()) {
// find the entry for the known variable, if any. Exclude the location where the variable is assigned with next == "="
if (constantValues.find(tok->varId()) != constantValues.end() && tok->next()->str() != "=") {
constantValueUsages[tok->varId()].push_back(tok);
}
}
}
for (auto constantVar = constantVars.rbegin(); constantVar != constantVars.rend(); constantVar++) {
bool referenceFound = false;
std::list<Token*> usageList = constantValueUsages[constantVar->first];
for (Token* usage : usageList) {
// check if any usages of each known variable are a reference
if (Token::Match(usage->tokAt(-2), "(|[|,|{|return|%op% & %varid%", constantVar->first)) {
referenceFound = true;
break;
}
}
if (!referenceFound) {
// replace all usages of non-referenced known variables with their value
for (Token* usage : usageList) {
usage->str(constantValues[constantVar->first]);
}
Token* startTok = constantVar->second;
// remove variable assignment statement
while (startTok->next()->str() != ";")
startTok->deleteNext();
startTok->deleteNext();
// #8579 if we can we want another token to delete startTok. if we can't it doesn't matter
if (startTok->previous()) {
startTok->previous()->deleteNext();
} else if (startTok->next()) {
startTok->next()->deletePrevious();
} else {
startTok->deleteThis();
}
startTok = nullptr;
constantVar->second = nullptr;
ret = true;
}
}
}
// variable id for local, float/double, array variables
std::set<int> localvars;
std::set<int> floatvars;
std::set<int> arrays;
// auto variables..
for (Token *tok = list.front(); tok; tok = tok->next()) {
// Search for a block of code
Token * const start = const_cast<Token *>(startOfExecutableScope(tok));
if (!start)
continue;
for (const Token *tok2 = start->previous(); tok2 && !Token::Match(tok2, "[;{}]"); tok2 = tok2->previous()) {
if (tok2->varId() != 0)
localvars.insert(tok2->varId());
}
tok = start;
// parse the block of code..
int indentlevel = 0;
Token *tok2 = tok;
for (; tok2; tok2 = tok2->next()) {
if (Token::Match(tok2, "[;{}] %type% %name%|*")) {
bool isfloat = false;
bool ispointer = false;
const Token *vartok = tok2->next();
while (Token::Match(vartok, "%name%|* %name%|*")) {
if (Token::Match(vartok, "float|double"))
isfloat = true;
if (vartok->str() == "*")
ispointer = true;
vartok = vartok->next();
}
if (Token::Match(vartok, "%var% ;|["))
localvars.insert(vartok->varId());
if (isfloat && !ispointer && Token::Match(vartok, "%var% ;"))
floatvars.insert(vartok->varId());
if (Token::Match(vartok, "%var% ["))
arrays.insert(vartok->varId());
}
if (tok2->str() == "{")
++indentlevel;
else if (tok2->str() == "}") {
--indentlevel;
if (indentlevel <= 0)
break;
}
else if (Token::simpleMatch(tok2, "for ("))
tok2 = tok2->next()->link();
else if (tok2->previous()->str() != "*" && !Token::Match(tok2->tokAt(-2), "* --|++") &&
(Token::Match(tok2, "%name% = %bool%|%char%|%num%|%str%|%name% ;") ||
Token::Match(tok2, "%name% [ %num%| ] = %str% ;") ||
Token::Match(tok2, "%name% = & %name% ;") ||
(Token::Match(tok2, "%name% = & %name% [ 0 ] ;") && arrays.find(tok2->tokAt(3)->varId()) != arrays.end()))) {
const int varid = tok2->varId();
if (varid == 0)
continue;
if (Token::Match(tok2->previous(), "[;{}]") && localvars.find(varid) == localvars.end())
continue;
// initialization of static variable => the value is not *known*
{
bool isstatic = false;
const Token *decl = tok2->previous();
while (decl && (decl->isName() || decl->str() == "*")) {
if (decl->str() == "static") {
isstatic = true;
break;
}
decl = decl->previous();
}
if (isstatic)
continue;
}
// skip loop variable
if (Token::Match(tok2->tokAt(-2), "(|:: %type%")) {
const Token *tok3 = tok2->previous();
do {
tok3 = tok3->tokAt(-2);
} while (Token::Match(tok3->previous(), ":: %type%"));
if (Token::Match(tok3->tokAt(-2), "for ( %type%"))
continue;
}
// struct name..
if (Token::Match(tok2, "%varid% = &| %varid%", tok2->varId()))
continue;
const std::string structname = Token::Match(tok2->tokAt(-3), "[;{}] %name% .") ?
std::string(tok2->strAt(-2) + " .") :
std::string();
const Token * const valueToken = tok2->tokAt(2);
std::string value;
nonneg int valueVarId = 0;
Token *tok3 = nullptr;
bool valueIsPointer = false;
// there could be a hang here if tok2 is moved back by the function calls below for some reason
if (Settings::terminated())
return false;
if (!simplifyKnownVariablesGetData(varid, &tok2, &tok3, value, valueVarId, valueIsPointer, floatvars.find(tok2->varId()) != floatvars.end()))
continue;
if (valueVarId > 0 && arrays.find(valueVarId) != arrays.end())
continue;
ret |= simplifyKnownVariablesSimplify(&tok2, tok3, varid, structname, value, valueVarId, valueIsPointer, valueToken, indentlevel);
}
else if (Token::Match(tok2, "strcpy|sprintf ( %name% , %str% ) ;")) {
const int varid(tok2->tokAt(2)->varId());
if (varid == 0)
continue;
const Token * const valueToken = tok2->tokAt(4);
std::string value(valueToken->str());
if (tok2->str() == "sprintf") {
std::string::size_type n = 0;
while ((n = value.find("%%", n)) != std::string::npos) {
// Replace "%%" with "%" - erase the first '%' and continue past the second '%'
value.erase(n, 1);
++n;
}
}
const int valueVarId(0);
const bool valueIsPointer(false);
Token *tok3 = tok2->tokAt(6);
ret |= simplifyKnownVariablesSimplify(&tok2, tok3, varid, emptyString, value, valueVarId, valueIsPointer, valueToken, indentlevel);
// there could be a hang here if tok2 was moved back by the function call above for some reason
if (Settings::terminated())
return false;
}
}
if (tok2)
tok = tok2->previous();
}
return ret;
}
bool Tokenizer::simplifyKnownVariablesGetData(nonneg int varid, Token **_tok2, Token **_tok3, std::string &value, nonneg int &valueVarId, bool &valueIsPointer, bool floatvar)
{
Token *tok2 = *_tok2;
Token *tok3 = nullptr;
if (Token::simpleMatch(tok2->tokAt(-2), "for (")) {
// only specific for loops is handled
if (!Token::Match(tok2, "%varid% = %num% ; %varid% <|<= %num% ; ++| %varid% ++| ) {", varid))
return false;
// is there a "break" in the for loop?
bool hasbreak = false;
const Token* end4 = tok2->linkAt(-1)->linkAt(1);
for (const Token *tok4 = tok2->previous()->link(); tok4 != end4; tok4 = tok4->next()) {
if (tok4->str() == "break") {
hasbreak = true;
break;
}
}
if (hasbreak)
return false;
// no break => the value of the counter value is known after the for loop..
const Token* compareTok = tok2->tokAt(5);
if (compareTok->str() == "<") {
value = compareTok->next()->str();
valueVarId = compareTok->next()->varId();
} else
value = MathLib::toString(MathLib::toLongNumber(compareTok->next()->str()) + 1);
// Skip for-body..
tok3 = tok2->previous()->link()->next()->link()->next();
} else {
value = tok2->strAt(2);
valueVarId = tok2->tokAt(2)->varId();
if (tok2->strAt(1) == "[") {
value = tok2->next()->link()->strAt(2);
valueVarId = 0;
} else if (value == "&") {
value = tok2->strAt(3);
valueVarId = tok2->tokAt(3)->varId();
// *ptr = &var; *ptr = 5;
// equals
// var = 5; not *var = 5;
if (tok2->strAt(4) == ";")
valueIsPointer = true;
}
// Add a '.0' to a decimal value and therefore convert it to an floating point number.
else if (MathLib::isDec(tok2->strAt(2)) && floatvar) {
value += ".0";
}
// float variable: convert true/false to 1.0 / 0.0
else if (tok2->tokAt(2)->isBoolean() && floatvar) {
value = (value == "true") ? "1.0" : "0.0";
}
if (Token::simpleMatch(tok2->next(), "= &"))
tok2 = tok2->tokAt(3);
tok3 = tok2->next();
}
*_tok2 = tok2;
*_tok3 = tok3;
return true;
}
bool Tokenizer::simplifyKnownVariablesSimplify(Token **tok2, Token *tok3, nonneg int varid, const std::string &structname, std::string &value, nonneg int valueVarId, bool valueIsPointer, const Token * const valueToken, int indentlevel) const
{
const bool pointeralias(valueToken->isName() || Token::Match(valueToken, "& %name% ["));
const bool varIsGlobal = (indentlevel == 0);
const bool printDebug = mSettings->debugwarnings;
if (mErrorLogger && !list.getFiles().empty())
mErrorLogger->reportProgress(list.getFiles()[0], "Tokenize (simplifyKnownVariables)", tok3->progressValue());
if (isMaxTime())
return false;
bool ret = false;
Token* bailOutFromLoop = nullptr;
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% * %name% ; %name% = & %name% ;") &&
(*tok2)->strAt(-5) == (*tok2)->strAt(-3)) {
(*tok2) = (*tok2)->tokAt(-4);
Token::eraseTokens((*tok2), (*tok2)->tokAt(6));
}
break;
}
}
// Stop if there is a pointer alias and a shadow variable is
// declared in an inner scope (#3058)
if (valueIsPointer && tok3->varId() > 0 &&
tok3->previous() && (tok3->previous()->isName() || tok3->previous()->str() == "*") &&
valueToken->str() == "&" &&
valueToken->next() &&
valueToken->next()->isName() &&
tok3->str() == valueToken->next()->str() &&
tok3->varId() > valueToken->next()->varId()) {
// more checking if this is a variable declaration
bool decl = true;
for (const Token *tok4 = tok3->previous(); tok4; tok4 = tok4->previous()) {
if (Token::Match(tok4, "[;{}]"))
break;
else if (tok4->isName()) {
if (tok4->varId() > 0) {
decl = false;
break;
}
}
else if (!Token::Match(tok4, "[&*]")) {
decl = false;
break;
}
}
if (decl)
break;
}
// Stop if label is found
if (Token::Match(tok3, "; %type% : ;"))
break;
// Stop if break/continue is found ..
if (Token::Match(tok3, "break|continue"))
break;
if ((indentlevel3 > 1 || !Token::simpleMatch(Token::findsimplematch(tok3,";"), "; }")) && tok3->str() == "return")
ret3 = true;
if (ret3 && tok3->str() == ";")
break;
if (pointeralias && Token::Match(tok3, ("!!= " + value).c_str()))
break;
// Stop if a loop is found
if (pointeralias && Token::Match(tok3, "do|for|while"))
break;
// Stop if unknown function call is seen and the variable is global: it might be
// changed by the function call
if (varIsGlobal && tok3->str() == ")" && tok3->link() &&
Token::Match(tok3->link()->tokAt(-2), "[;{}] %name% (") &&
!Token::Match(tok3->link()->previous(), "if|for|while|switch|BOOST_FOREACH"))
break;
// Stop if something like 'while (--var)' is found
if (Token::Match(tok3, "for|while|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 = nullptr;
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() &&
tok3->previous()->link()->strAt(-1) != "if")
bailOutFromLoop = tok3->link();
continue;
}
// Variable used in realloc (see Ticket #1649)
if (Token::Match(tok3, "%name% = realloc ( %name% ,") &&
tok3->varId() == varid &&
tok3->tokAt(4)->varId() == varid) {
tok3->tokAt(4)->str(value);
ret = true;
}
// condition "(|&&|%OROR% %varid% )|&&|%OROR%|;
if (!Token::Match(tok3->previous(), "( %name% )") &&
Token::Match(tok3->previous(), "&&|(|%oror% %varid% &&|%oror%|)|;", varid)) {
tok3->str(value);
tok3->varId(valueVarId);
ret = true;
}
// parameter in function call..
if (tok3->varId() == varid && Token::Match(tok3->previous(), "[(,] %name% [,)]")) {
// If the parameter is passed by value then simplify it
if (isFunctionParameterPassedByValue(tok3)) {
tok3->str(value);
tok3->varId(valueVarId);
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 (printDebug) {
// 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(), ". %name% ("))
break;
// suppress debug-warning when assignment
if (tok3->strAt(1) == "=")
break;
// taking address of variable..
if (Token::Match(tok3->tokAt(-2), "return|= & %name% ;"))
break;
// parameter in function call..
if (Token::Match(tok3->tokAt(-2), "%name% ( %name% ,|)") ||
Token::Match(tok3->previous(), ", %name% ,|)"))
break;
// conditional increment
if (Token::Match(tok3->tokAt(-3), ") { ++|--") ||
Token::Match(tok3->tokAt(-2), ") { %name% ++|--"))
break;
reportError(tok3, Severity::debug, "debug",
"simplifyKnownVariables: bailing out (variable="+tok3->str()+", value="+value+")");
}
break;
}
// Using the variable in condition..
if (Token::Match(tok3->previous(), ("if ( " + structname + " %varid% %cop%|)").c_str(), varid) ||
Token::Match(tok3, ("( " + structname + " %varid% %comp%").c_str(), varid) ||
Token::Match(tok3, ("%comp%|!|= " + structname + " %varid% %cop%|)|;").c_str(), varid) ||
Token::Match(tok3->previous(), "strlen|free ( %varid% )", varid)) {
if (value[0] == '\"' && tok3->previous()->str() != "strlen") {
// bail out if value is a string unless if it's just given
// as parameter to strlen
break;
}
if (!structname.empty()) {
tok3->deleteNext(2);
}
if (Token::Match(valueToken, "& %name% ;")) {
tok3->insertToken("&");
tok3 = tok3->next();
}
tok3 = tok3->next();
tok3->str(value);
tok3->varId(valueVarId);
ret = true;
}
// pointer alias used in condition..
if (Token::Match(valueToken,"& %name% ;") && Token::Match(tok3, ("( * " + structname + " %varid% %cop%").c_str(), varid)) {
tok3->deleteNext();
if (!structname.empty())
tok3->deleteNext(2);
tok3 = tok3->next();
tok3->str(value);
tok3->varId(valueVarId);
ret = true;
}
// Delete pointer alias
if (isCPP() && pointeralias && (tok3->str() == "delete") && tok3->next() &&
(Token::Match(tok3->next(), "%varid% ;", varid) ||
Token::Match(tok3->next(), "[ ] %varid%", varid))) {
tok3 = (tok3->next()->str() == "[") ? tok3->tokAt(3) : tok3->next();
tok3->str(value);
tok3->varId(valueVarId);
ret = true;
}
// Variable is used in function call..
if (Token::Match(tok3, ("%name% ( " + structname + " %varid% ,").c_str(), varid)) {
static const char * const functionName[] = {
// always simplify
"strcmp", "strdup",
// don't simplify buffer value
"memcmp","memcpy","memmove","memset","strcpy","strncmp","strncpy"
};
for (int i = 0; i < (sizeof(functionName) / sizeof(*functionName)); ++i) {
if (valueVarId == 0U && i >= 2)
break;
if (tok3->str() == functionName[i]) {
Token *par1 = tok3->tokAt(2);
if (!structname.empty()) {
par1->deleteNext();
par1->deleteThis();
}
par1->str(value);
par1->varId(valueVarId);
break;
}
}
}
// Variable is used as 2nd parameter in function call..
if (Token::Match(tok3, ("%name% ( %any% , " + structname + " %varid% ,|)").c_str(), varid)) {
static const char * const functionName[] = {
// always simplify
"strcmp","strcpy","strncmp","strncpy",
// don't simplify buffer value
"memcmp","memcpy","memmove"
};
for (int i = 0; i < (sizeof(functionName) / sizeof(*functionName)); ++i) {
if (valueVarId == 0U && i >= 4)
break;
if (tok3->str() == functionName[i]) {
Token *par = tok3->tokAt(4);
if (!structname.empty()) {
par->deleteNext();
par->deleteThis();
}
par->str(value);
par->varId(valueVarId);
break;
}
}
}
// array usage
if (value[0] != '\"' && Token::Match(tok3, ("[(,] " + structname + " %varid% [|%cop%").c_str(), varid)) {
if (!structname.empty()) {
tok3->deleteNext(2);
}
tok3 = tok3->next();
tok3->str(value);
tok3->varId(valueVarId);
ret = true;
}
// The >> operator is sometimes used to assign a variable in C++
if (isCPP() && Token::Match(tok3, (">> " + structname + " %varid%").c_str(), varid)) {
// bailout for such code: ; std :: cin >> i ;
const Token *prev = tok3->previous();
while (prev && prev->str() != "return" && Token::Match(prev, "%name%|::|*"))
prev = prev->previous();
if (Token::Match(prev, ";|{|}|>>"))
break;
}
// 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 + " %name% =").c_str())) ||
Token::Match(tok3, ("[(=+-*/%^|[] " + structname + " %varid% <<|>>").c_str(), varid) ||
Token::Match(tok3, ("<<|>> " + structname + " %varid% %cop%|;|]|)").c_str(), varid) ||
Token::Match(tok3->previous(), ("[=+-*/%^|[] ( " + structname + " %varid% !!=").c_str(), varid)) {
if (value[0] == '\"')
break;
if (!structname.empty()) {
tok3->deleteNext(2);
ret = true;
}
tok3 = tok3->next();
if (tok3->str() != value)
ret = true;
tok3->str(value);
tok3->varId(valueVarId);
if (tok3->previous()->str() == "*" && (valueIsPointer || Token::Match(valueToken, "& %name% ;"))) {
tok3 = tok3->previous();
tok3->deleteThis();
ret = true;
} else if (Token::Match(valueToken, "& %name% ;"))
tok3->insertToken("&", emptyString, true);
}
if (Token::simpleMatch(tok3, "= {")) {
const Token* const end4 = tok3->linkAt(1);
for (const Token *tok4 = tok3; tok4 != end4; tok4 = tok4->next()) {
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 (Token::Match(tok4, "(|)"))
break;
// Replace variable used in condition..
if (Token::Match(tok4, "; %name% <|<=|!= %name% ; ++| %name% ++| )")) {
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% ;")) {
tok3->deleteNext(3);
} else {
tok3 = tok3->next();
tok3->str(value);
tok3->varId(valueVarId);
tok3->deleteNext();
}
value = MathLib::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), "[.[]")) {
value = MathLib::incdec(value, tok3->next()->str());
(*tok2)->tokAt(2)->str(value);
(*tok2)->tokAt(2)->varId(valueVarId);
if (Token::Match(tok3, "[;{}] %any% %any% ;")) {
tok3->deleteNext(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) &&
valueToken->str() != "&" &&
(tok3->tokAt(2)->isExtendedOp() || tok3->strAt(2) == ";") &&
value[0] != '\"') {
tok3->next()->str(value);
tok3->next()->varId(valueVarId);
}
else if (pointeralias && Token::Match(tok3, "return * %varid% ;", varid) && value[0] != '\"') {
tok3->deleteNext();
tok3->next()->str(value);
tok3->next()->varId(valueVarId);
}
}
return ret;
}
void Tokenizer::elseif() void Tokenizer::elseif()
{ {
for (Token *tok = list.front(); tok; tok = tok->next()) { for (Token *tok = list.front(); tok; tok = tok->next()) {
@ -8162,71 +7399,6 @@ bool Tokenizer::isScopeNoReturn(const Token *endScopeToken, bool *unknown) const
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
bool Tokenizer::isFunctionParameterPassedByValue(const Token *fpar) const
{
// TODO: If symbol database is available, use it.
const Token *ftok;
// Look at function call, what parameter number is it?
int parameter = 1;
for (ftok = fpar->previous(); ftok; ftok = ftok->previous()) {
if (ftok->str() == "(")
break;
else if (ftok->str() == ")")
ftok = ftok->link();
else if (ftok->str() == ",")
++parameter;
else if (Token::Match(ftok, "[;{}]"))
break;
}
// Is this a function call?
if (ftok && Token::Match(ftok->tokAt(-2), "[;{}=] %name% (")) {
const std::string& functionName(ftok->previous()->str());
if (functionName == "return")
return true;
// Locate function declaration..
for (const Token *tok = tokens(); tok; tok = tok->next()) {
if (tok->str() == "{")
tok = tok->link();
else if (Token::Match(tok, "%type% (") && tok->str() == functionName) {
// Goto parameter
tok = tok->tokAt(2);
int par = 1;
while (tok && par < parameter) {
if (tok->str() == ")")
break;
if (tok->str() == ",")
++par;
tok = tok->next();
}
if (!tok)
return false;
// If parameter was found, determine if it's passed by value
if (par == parameter) {
bool knowntype = false;
while (tok && tok->isName()) {
knowntype |= tok->isStandardType();
knowntype |= (tok->str() == "struct");
tok = tok->next();
}
if (!tok || !knowntype)
return false;
if (tok->str() != "," && tok->str() != ")")
return false;
return true;
}
}
}
}
return false;
}
//---------------------------------------------------------------------------
void Tokenizer::eraseDeadCode(Token *begin, const Token *end) void Tokenizer::eraseDeadCode(Token *begin, const Token *end)
{ {
if (!begin) if (!begin)

View File

@ -329,27 +329,6 @@ public:
*/ */
bool simplifyUsing(); bool simplifyUsing();
/**
* A simplify function that replaces a variable with its value in cases
* when the value is known. e.g. "x=10; if(x)" => "x=10;if(10)"
*
* @return true if modifications to token-list are done.
* false if no modifications are done.
*/
bool simplifyKnownVariables();
/**
* Utility function for simplifyKnownVariables. Get data about an
* assigned variable.
*/
static bool simplifyKnownVariablesGetData(nonneg int varid, Token **_tok2, Token **_tok3, std::string &value, nonneg int &valueVarId, bool &valueIsPointer, bool floatvar);
/**
* utility function for simplifyKnownVariables. Perform simplification
* of a given variable
*/
bool simplifyKnownVariablesSimplify(Token **tok2, Token *tok3, nonneg int varid, const std::string &structname, std::string &value, nonneg int valueVarId, bool valueIsPointer, const Token * const valueToken, int indentlevel) const;
/** Simplify useless C++ empty namespaces, like: 'namespace %name% { }'*/ /** Simplify useless C++ empty namespaces, like: 'namespace %name% { }'*/
void simplifyEmptyNamespaces(); void simplifyEmptyNamespaces();

View File

@ -191,6 +191,7 @@ private:
TEST_CASE(array_index_64); // #10878 TEST_CASE(array_index_64); // #10878
TEST_CASE(array_index_65); // #11066 TEST_CASE(array_index_65); // #11066
TEST_CASE(array_index_66); // #10740 TEST_CASE(array_index_66); // #10740
TEST_CASE(array_index_67); // #1596
TEST_CASE(array_index_multidim); TEST_CASE(array_index_multidim);
TEST_CASE(array_index_switch_in_for); TEST_CASE(array_index_switch_in_for);
TEST_CASE(array_index_for_in_for); // FP: #2634 TEST_CASE(array_index_for_in_for); // FP: #2634
@ -1852,6 +1853,25 @@ private:
errout.str()); errout.str());
} }
void array_index_67() {
check("void func(int i) {\n" // #1596
" int types[3];\n"
" int type_cnt = 0;\n"
" if (i == 0) {\n"
" types[type_cnt] = 0;\n"
" type_cnt++;\n"
" types[type_cnt] = 0;\n"
" type_cnt++;\n"
" types[type_cnt] = 0;\n"
" type_cnt++;\n"
" } else {\n"
" types[type_cnt] = 1;\n"
" type_cnt++;\n"
" }\n"
"}\n");
ASSERT_EQUALS("", errout.str());
}
void array_index_multidim() { void array_index_multidim() {
check("void f()\n" check("void f()\n"
"{\n" "{\n"

View File

@ -93,6 +93,7 @@ private:
TEST_CASE(assign21); // #10186 TEST_CASE(assign21); // #10186
TEST_CASE(assign22); // #9139 TEST_CASE(assign22); // #9139
TEST_CASE(assign23); TEST_CASE(assign23);
TEST_CASE(assign24); // #7440
TEST_CASE(isAutoDealloc); TEST_CASE(isAutoDealloc);
@ -504,6 +505,23 @@ private:
settings = s; settings = s;
} }
void assign24() { // #7440
check("void f() {\n"
" char* data = new char[100];\n"
" char** dataPtr = &data;\n"
" delete[] *dataPtr;\n"
"}\n", true);
ASSERT_EQUALS("", errout.str());
check("void f() {\n"
" char* data = new char[100];\n"
" char** dataPtr = &data;\n"
" printf(\"test\");\n"
" delete[] *dataPtr;\n"
"}\n", true);
ASSERT_EQUALS("", errout.str());
}
void isAutoDealloc() { void isAutoDealloc() {
check("void f() {\n" check("void f() {\n"
" char *p = new char[100];" " char *p = new char[100];"

View File

@ -57,7 +57,6 @@ private:
TEST_CASE(toDoubleNumber); TEST_CASE(toDoubleNumber);
TEST_CASE(naninf); TEST_CASE(naninf);
TEST_CASE(isNullValue); TEST_CASE(isNullValue);
TEST_CASE(incdec);
TEST_CASE(sin); TEST_CASE(sin);
TEST_CASE(cos); TEST_CASE(cos);
TEST_CASE(tan); TEST_CASE(tan);
@ -1192,27 +1191,6 @@ private:
ASSERT_EQUALS(false, MathLib::isNullValue("-ENOMEM")); ASSERT_EQUALS(false, MathLib::isNullValue("-ENOMEM"));
} }
void incdec() const {
// increment
{
const MathLib::biguint num = ~10U;
const std::string op = "++";
const std::string strNum = MathLib::incdec(MathLib::toString(num), op);
const MathLib::biguint incrementedNum = MathLib::toULongNumber(strNum);
ASSERT_EQUALS(num + 1U, incrementedNum);
}
// decrement
{
const MathLib::biguint num = ~10U;
const std::string op = "--";
const std::string strNum = MathLib::incdec(MathLib::toString(num), op);
const MathLib::biguint decrementedNum = MathLib::toULongNumber(strNum);
ASSERT_EQUALS(num - 1U, decrementedNum);
}
// invalid operation
ASSERT_THROW(MathLib::incdec("1", "x"), InternalError); // throw
}
void sin() const { void sin() const {
ASSERT_EQUALS("0.0", MathLib::sin("0")); ASSERT_EQUALS("0.0", MathLib::sin("0"));
} }

View File

@ -64,6 +64,7 @@ private:
TEST_CASE(zeroDiv11); TEST_CASE(zeroDiv11);
TEST_CASE(zeroDiv12); TEST_CASE(zeroDiv12);
TEST_CASE(zeroDiv13); TEST_CASE(zeroDiv13);
TEST_CASE(zeroDiv14); // #1169
TEST_CASE(zeroDivCond); // division by zero / useless condition TEST_CASE(zeroDivCond); // division by zero / useless condition
@ -587,6 +588,17 @@ private:
ASSERT_EQUALS("[test.cpp:4]: (error) Division by zero.\n", errout.str()); ASSERT_EQUALS("[test.cpp:4]: (error) Division by zero.\n", errout.str());
} }
void zeroDiv14() {
check("void f() {\n" // #1169
" double dx = 1.;\n"
" int ix = 1;\n"
" int i = 1;\n"
" std::cout << ix / (i >> 1) << std::endl;\n"
" std::cout << dx / (i >> 1) << std::endl;\n"
"}\n");
ASSERT_EQUALS("[test.cpp:5]: (error) Division by zero.\n", errout.str());
}
void zeroDivCond() { void zeroDivCond() {
check("void f(unsigned int x) {\n" check("void f(unsigned int x) {\n"
" int y = 17 / x;\n" " int y = 17 / x;\n"

View File

@ -101,9 +101,7 @@ private:
TEST_CASE(simplifyArrayAccessSyntax); TEST_CASE(simplifyArrayAccessSyntax);
TEST_CASE(pointeralias1); TEST_CASE(pointeralias1);
TEST_CASE(pointeralias2);
TEST_CASE(pointeralias3); TEST_CASE(pointeralias3);
TEST_CASE(pointeralias4);
// struct ABC { } abc; => struct ABC { }; ABC abc; // struct ABC { } abc; => struct ABC { }; ABC abc;
TEST_CASE(simplifyStructDecl1); TEST_CASE(simplifyStructDecl1);
@ -137,58 +135,36 @@ private:
TEST_CASE(simplifyNamespaceAliases1); TEST_CASE(simplifyNamespaceAliases1);
TEST_CASE(simplifyNamespaceAliases2); // ticket #10281 TEST_CASE(simplifyNamespaceAliases2); // ticket #10281
TEST_CASE(simplifyKnownVariables1);
TEST_CASE(simplifyKnownVariables2); TEST_CASE(simplifyKnownVariables2);
TEST_CASE(simplifyKnownVariables3); TEST_CASE(simplifyKnownVariables3);
TEST_CASE(simplifyKnownVariables4); TEST_CASE(simplifyKnownVariables4);
TEST_CASE(simplifyKnownVariables5); TEST_CASE(simplifyKnownVariables5);
TEST_CASE(simplifyKnownVariables6);
TEST_CASE(simplifyKnownVariables7);
TEST_CASE(simplifyKnownVariables8);
TEST_CASE(simplifyKnownVariables9);
TEST_CASE(simplifyKnownVariables10);
TEST_CASE(simplifyKnownVariables11);
TEST_CASE(simplifyKnownVariables13); TEST_CASE(simplifyKnownVariables13);
TEST_CASE(simplifyKnownVariables14); TEST_CASE(simplifyKnownVariables14);
TEST_CASE(simplifyKnownVariables15);
TEST_CASE(simplifyKnownVariables16); TEST_CASE(simplifyKnownVariables16);
TEST_CASE(simplifyKnownVariables17); TEST_CASE(simplifyKnownVariables17);
TEST_CASE(simplifyKnownVariables18); TEST_CASE(simplifyKnownVariables18);
TEST_CASE(simplifyKnownVariables19); TEST_CASE(simplifyKnownVariables19);
TEST_CASE(simplifyKnownVariables20);
TEST_CASE(simplifyKnownVariables21); TEST_CASE(simplifyKnownVariables21);
TEST_CASE(simplifyKnownVariables22);
TEST_CASE(simplifyKnownVariables23);
TEST_CASE(simplifyKnownVariables25); TEST_CASE(simplifyKnownVariables25);
TEST_CASE(simplifyKnownVariables27);
TEST_CASE(simplifyKnownVariables28);
// FIXME Does expression id handle these? TEST_CASE(simplifyKnownVariables29); // ticket #1811 // FIXME Does expression id handle these? TEST_CASE(simplifyKnownVariables29); // ticket #1811
TEST_CASE(simplifyKnownVariables30); TEST_CASE(simplifyKnownVariables30);
TEST_CASE(simplifyKnownVariables31);
TEST_CASE(simplifyKnownVariables32); // const
TEST_CASE(simplifyKnownVariables33); // struct variable
TEST_CASE(simplifyKnownVariables34); TEST_CASE(simplifyKnownVariables34);
TEST_CASE(simplifyKnownVariables36); // ticket #2304 - known value for strcpy parameter TEST_CASE(simplifyKnownVariables36); // ticket #2304 - known value for strcpy parameter
TEST_CASE(simplifyKnownVariables39);
TEST_CASE(simplifyKnownVariables41); // p=&x; if (p) ..
TEST_CASE(simplifyKnownVariables42); // ticket #2031 - known string value after strcpy TEST_CASE(simplifyKnownVariables42); // ticket #2031 - known string value after strcpy
TEST_CASE(simplifyKnownVariables43); TEST_CASE(simplifyKnownVariables43);
TEST_CASE(simplifyKnownVariables44); // ticket #3117 - don't simplify static variables TEST_CASE(simplifyKnownVariables44); // ticket #3117 - don't simplify static variables
TEST_CASE(simplifyKnownVariables45); // ticket #3281 - static constant variable not simplified
TEST_CASE(simplifyKnownVariables46); // ticket #3587 - >> TEST_CASE(simplifyKnownVariables46); // ticket #3587 - >>
TEST_CASE(simplifyKnownVariables47); // ticket #3627 - >> TEST_CASE(simplifyKnownVariables47); // ticket #3627 - >>
TEST_CASE(simplifyKnownVariables48); // ticket #3754 - wrong simplification in for loop header TEST_CASE(simplifyKnownVariables48); // ticket #3754 - wrong simplification in for loop header
TEST_CASE(simplifyKnownVariables49); // #3691 - continue in switch TEST_CASE(simplifyKnownVariables49); // #3691 - continue in switch
TEST_CASE(simplifyKnownVariables50); // #4066 sprintf changes TEST_CASE(simplifyKnownVariables50); // #4066 sprintf changes
TEST_CASE(simplifyKnownVariables51); // #4409 hang TEST_CASE(simplifyKnownVariables51); // #4409 hang
TEST_CASE(simplifyKnownVariables53); // references
TEST_CASE(simplifyKnownVariables54); // #4913 'x' is not 0 after *--x=0; TEST_CASE(simplifyKnownVariables54); // #4913 'x' is not 0 after *--x=0;
TEST_CASE(simplifyKnownVariables55); // pointer alias
TEST_CASE(simplifyKnownVariables56); // ticket #5301 - >> TEST_CASE(simplifyKnownVariables56); // ticket #5301 - >>
TEST_CASE(simplifyKnownVariables57); // ticket #4724 TEST_CASE(simplifyKnownVariables57); // ticket #4724
TEST_CASE(simplifyKnownVariables58); // ticket #5268 TEST_CASE(simplifyKnownVariables58); // ticket #5268
TEST_CASE(simplifyKnownVariables59); // skip for header TEST_CASE(simplifyKnownVariables59); // skip for header
TEST_CASE(simplifyKnownVariables60); // #6829
TEST_CASE(simplifyKnownVariables61); // #7805 TEST_CASE(simplifyKnownVariables61); // #7805
TEST_CASE(simplifyKnownVariables62); // #5666 - p=&str[0] TEST_CASE(simplifyKnownVariables62); // #5666 - p=&str[0]
TEST_CASE(simplifyKnownVariables63); // #10798 TEST_CASE(simplifyKnownVariables63); // #10798
@ -203,11 +179,8 @@ private:
TEST_CASE(simplifyKnownVariablesClassMember); // #2815 - value of class member may be changed by function call TEST_CASE(simplifyKnownVariablesClassMember); // #2815 - value of class member may be changed by function call
TEST_CASE(simplifyKnownVariablesFunctionCalls); // Function calls (don't assume pass by reference) TEST_CASE(simplifyKnownVariablesFunctionCalls); // Function calls (don't assume pass by reference)
TEST_CASE(simplifyKnownVariablesGlobalVars); TEST_CASE(simplifyKnownVariablesGlobalVars);
TEST_CASE(simplifyKnownVariablesPointerAliasFunctionCall); // #7440
TEST_CASE(simplifyKnownVariablesNamespace); // #10059 TEST_CASE(simplifyKnownVariablesNamespace); // #10059
TEST_CASE(simplify_constants2);
TEST_CASE(simplify_constants4);
TEST_CASE(simplify_constants6); // Ticket #5625: Ternary operator as template parameter TEST_CASE(simplify_constants6); // Ticket #5625: Ternary operator as template parameter
TEST_CASE(simplifyVarDeclInitLists); TEST_CASE(simplifyVarDeclInitLists);
} }
@ -2607,16 +2580,6 @@ private:
} }
} }
void pointeralias2() {
const char code[] = "void f()\n"
"{\n"
" int i;\n"
" int *p = &i;\n"
" return *p;\n"
"}\n";
ASSERT_EQUALS("void f ( ) { int i ; int * p ; return i ; }", tok(code));
}
void pointeralias3() { void pointeralias3() {
const char code[] = "void f()\n" const char code[] = "void f()\n"
"{\n" "{\n"
@ -2635,18 +2598,6 @@ private:
ASSERT_EQUALS(expected, tok(code)); ASSERT_EQUALS(expected, tok(code));
} }
void pointeralias4() {
const char code[] = "int f()\n"
"{\n"
" int i;\n"
" int *p = &i;\n"
" *p = 5;\n"
" return i;\n"
"}\n";
const char expected[] = "int f ( ) { int i ; int * p ; i = 5 ; return 5 ; }";
ASSERT_EQUALS(expected, tok(code));
}
void simplifyStructDecl1() { void simplifyStructDecl1() {
{ {
const char code[] = "struct ABC { } abc;"; const char code[] = "struct ABC { } abc;";
@ -3228,37 +3179,9 @@ private:
std::istringstream istr(code); std::istringstream istr(code);
ASSERT_LOC(tokenizer.tokenize(istr, "test.cpp"), file, line); ASSERT_LOC(tokenizer.tokenize(istr, "test.cpp"), file, line);
(tokenizer.simplifyKnownVariables)();
return tokenizer.tokens()->stringifyList(nullptr, false); return tokenizer.tokens()->stringifyList(nullptr, false);
} }
void simplifyKnownVariables1() {
{
const char code[] = "void f()\n"
"{\n"
" int a = 10;\n"
" if (a);\n"
"}\n";
ASSERT_EQUALS(
"void f ( ) { int a ; a = 10 ; if ( 10 ) { ; } }",
simplifyKnownVariables(code));
}
{
const char code[] = "void f()\n"
"{\n"
" int a = 10;\n"
" if (!a);\n"
"}\n";
ASSERT_EQUALS(
"void f ( ) { int a ; a = 10 ; if ( ! 10 ) { ; } }",
simplifyKnownVariables(code));
}
}
void simplifyKnownVariables2() { void simplifyKnownVariables2() {
const char code[] = "void f()\n" const char code[] = "void f()\n"
"{\n" "{\n"
@ -3313,136 +3236,6 @@ private:
simplifyKnownVariables(code)); simplifyKnownVariables(code));
} }
void simplifyKnownVariables6() {
const char code[] = "void f()\n"
"{\n"
" char str[2];"
" int a = 4;\n"
" str[a] = 0;\n"
"}\n";
ASSERT_EQUALS(
"void f ( ) { char str [ 2 ] ; int a ; a = 4 ; str [ 4 ] = 0 ; }",
simplifyKnownVariables(code));
}
void simplifyKnownVariables7() {
const char code[] = "void foo()\n"
"{\n"
" int i = 22;\n"
" abc[i++] = 1;\n"
" abc[++i] = 2;\n"
"}\n";
ASSERT_EQUALS(
"void foo ( ) { int i ; i = 24 ; abc [ 22 ] = 1 ; abc [ 24 ] = 2 ; }",
simplifyKnownVariables(code));
}
void simplifyKnownVariables8() {
const char code[] = "void foo()\n"
"{\n"
" int i = 22;\n"
" i++;\n"
" abc[i] = 0;\n"
"}\n";
ASSERT_EQUALS(
"void foo ( ) { int i ; i = 23 ; abc [ 23 ] = 0 ; }",
simplifyKnownVariables(code));
}
void simplifyKnownVariables9() {
const char code[] = "void foo()\n"
"{\n"
" int a = 1, b = 2;\n"
" if (a < b)\n"
" ;\n"
"}\n";
ASSERT_EQUALS(
"void foo ( ) { int a ; a = 1 ; int b ; b = 2 ; if ( 1 < 2 ) { ; } }",
simplifyKnownVariables(code));
}
void simplifyKnownVariables10() {
{
const char code[] = "void f()\n"
"{\n"
" bool b=false;\n"
"\n"
" {\n"
" b = true;\n"
" }\n"
"\n"
" if( b )\n"
" {\n"
" a();\n"
" }\n"
"}\n";
const std::string expected1("void f ( ) {"
" bool b ; b = false ;"
" { b = true ; }");
TODO_ASSERT_EQUALS(
expected1 + " if ( true ) { a ( ) ; } }",
expected1 + " if ( b ) { a ( ) ; } }",
simplifyKnownVariables(code));
}
{
const char code[] = "void f()\n"
"{\n"
" bool b=false;\n"
" { b = false; }\n"
" {\n"
" b = true;\n"
" }\n"
"\n"
" if( b )\n"
" {\n"
" a();\n"
" }\n"
"}\n";
TODO_ASSERT_EQUALS(
"void f ( ) { bool b ; b = false ; { b = false ; } { b = true ; } if ( true ) { a ( ) ; } }",
"void f ( ) { bool b ; b = false ; { b = false ; } { b = true ; } if ( b ) { a ( ) ; } }",
simplifyKnownVariables(code));
}
{
const char code[] = "void f()\n"
"{\n"
" int b=0;\n"
" b = 1;\n"
" for( int i = 0; i < 10; i++ )"
" {\n"
" }\n"
"\n"
" return b;\n"
"}\n";
ASSERT_EQUALS(
"void f ( ) { int b ; b = 0 ; b = 1 ; for ( int i = 0 ; i < 10 ; i ++ ) { } return 1 ; }",
simplifyKnownVariables(code));
}
}
void simplifyKnownVariables11() {
const char code[] = "const int foo = 0;\n"
"int main()\n"
"{\n"
" int foo=0;\n"
"}\n";
ASSERT_EQUALS(
"int main ( ) { int foo ; foo = 0 ; }",
simplifyKnownVariables(code));
}
void simplifyKnownVariables13() { void simplifyKnownVariables13() {
const char code[] = "void f()\n" const char code[] = "void f()\n"
"{\n" "{\n"
@ -3461,32 +3254,6 @@ private:
ASSERT_EQUALS(code, simplifyKnownVariables(code)); ASSERT_EQUALS(code, simplifyKnownVariables(code));
} }
void simplifyKnownVariables15() {
{
const char code[] = "int main()\n"
"{\n"
" int x=5;\n"
" std::cout << 10 / x << std::endl;\n"
"}\n";
ASSERT_EQUALS(
"int main ( ) { int x ; x = 5 ; std :: cout << 10 / 5 << std :: endl ; }",
simplifyKnownVariables(code));
}
{
const char code[] = "int main()\n"
"{\n"
" int x=5;\n"
" std::cout << x / ( x == 1 ) << std::endl;\n"
"}\n";
ASSERT_EQUALS(
"int main ( ) { int x ; x = 5 ; std :: cout << 5 / ( 5 == 1 ) << std :: endl ; }",
simplifyKnownVariables(code));
}
}
void simplifyKnownVariables16() { void simplifyKnownVariables16() {
// ticket #807 - segmentation fault when macro isn't found // ticket #807 - segmentation fault when macro isn't found
const char code[] = "void f ( ) { int n = 1; DISPATCH(while); }"; const char code[] = "void f ( ) { int n = 1; DISPATCH(while); }";
@ -3515,111 +3282,12 @@ private:
simplifyKnownVariables(code)); simplifyKnownVariables(code));
} }
void simplifyKnownVariables20() {
const char code[] = "void f()\n"
"{\n"
" int i = 0;\n"
" if (x) {\n"
" if (i) i=0;\n"
" }\n"
"}\n";
ASSERT_EQUALS(
"void f ( ) { int i ; i = 0 ; if ( x ) { if ( 0 ) { i = 0 ; } } }",
simplifyKnownVariables(code));
}
void simplifyKnownVariables21() { void simplifyKnownVariables21() {
const char code[] = "void foo() { int n = 10; for (int i = 0; i < n; ++i) { } }";
ASSERT_EQUALS(
"void foo ( ) { int n ; n = 10 ; for ( int i = 0 ; i < 10 ; ++ i ) { } }",
simplifyKnownVariables(code));
ASSERT_EQUALS( ASSERT_EQUALS(
"void foo ( int i ) { int n ; n = i ; for ( i = 0 ; i < n ; ++ i ) { } }", "void foo ( int i ) { int n ; n = i ; for ( i = 0 ; i < n ; ++ i ) { } }",
simplifyKnownVariables("void foo(int i) { int n = i; for (i = 0; i < n; ++i) { } }")); simplifyKnownVariables("void foo(int i) { int n = i; for (i = 0; i < n; ++i) { } }"));
} }
void simplifyKnownVariables22() {
// This testcase is related to ticket #1169
{
const char code[] = "void foo()\n"
"{\n"
" int n = 10;\n"
" i = (n >> 1);\n"
"}\n";
ASSERT_EQUALS(
"void foo ( ) { int n ; n = 10 ; i = 10 >> 1 ; }",
simplifyKnownVariables(code));
}
{
const char code[] = "void foo()\n"
"{\n"
" int n = 10;\n"
" i = (n << 1);\n"
"}\n";
ASSERT_EQUALS(
"void foo ( ) { int n ; n = 10 ; i = 10 << 1 ; }",
simplifyKnownVariables(code));
}
{
const char code[] = "void foo()\n"
"{\n"
" int n = 10;\n"
" i = (1 << n);\n"
"}\n";
ASSERT_EQUALS(
"void foo ( ) { int n ; n = 10 ; i = 1 << 10 ; }",
simplifyKnownVariables(code));
}
{
const char code[] = "void foo()\n"
"{\n"
" int n = 10;\n"
" i = (1 >> n);\n"
"}\n";
ASSERT_EQUALS(
"void foo ( ) { int n ; n = 10 ; i = 1 >> 10 ; }",
simplifyKnownVariables(code));
}
}
void simplifyKnownVariables23() {
// This testcase is related to ticket #1596
const char code[] = "void foo(int x)\n"
"{\n"
" int a[10], c = 0;\n"
" if (x) {\n"
" a[c] = 0;\n"
" c++;\n"
" } else {\n"
" a[c] = 0;\n"
" }\n"
"}\n";
TODO_ASSERT_EQUALS(
"void foo ( int x ) "
"{"
" int a [ 10 ] ; int c ; c = 0 ;"
" if ( x ) { a [ 0 ] = 0 ; c = 1 ; }"
" else { a [ 0 ] = 0 ; } "
"}",
"void foo ( int x ) "
"{"
" int a [ 10 ] ; int c ; c = 0 ;"
" if ( x ) { a [ 0 ] = 0 ; c ++ ; }"
" else { a [ c ] = 0 ; } "
"}",
simplifyKnownVariables(code));
}
void simplifyKnownVariables25() { void simplifyKnownVariables25() {
{ {
// This testcase is related to ticket #1646 // This testcase is related to ticket #1646
@ -3672,43 +3340,6 @@ private:
} }
} }
void simplifyKnownVariables27() {
// This testcase is related to ticket #1633
const char code[] = "void foo()\n"
"{\n"
" int i1 = 1;\n"
" int i2 = 2;\n"
" int i3 = (i1 + i2) * 3;\n"
"}\n";
ASSERT_EQUALS(
"void foo ( ) "
"{"
" int i1 ; i1 = 1 ;"
" int i2 ; i2 = 2 ;"
" int i3 ; i3 = ( 1 + 2 ) * 3 ; "
"}",
simplifyKnownVariables(code));
}
void simplifyKnownVariables28() {
const char code[] = "void foo(int g)\n"
"{\n"
" int i = 2;\n"
" if (g) {\n"
" }\n"
" if (i > 0) {\n"
" }\n"
"}\n";
ASSERT_EQUALS(
"void foo ( int g ) "
"{"
" int i ; i = 2 ;"
" if ( g ) { }"
" if ( 2 > 0 ) { } "
"}",
simplifyKnownVariables(code));
}
void simplifyKnownVariables29() { // ticket #1811 void simplifyKnownVariables29() { // ticket #1811
{ {
const char code[] = "int foo(int u, int v)\n" const char code[] = "int foo(int u, int v)\n"
@ -4049,48 +3680,6 @@ private:
ASSERT_EQUALS(expected, tokenizeAndStringify(code, true)); ASSERT_EQUALS(expected, tokenizeAndStringify(code, true));
} }
void simplifyKnownVariables31() {
const char code[] = "void foo(const char str[]) {\n"
" const char *p = str;\n"
" if (p[0] == 0) {\n"
" }\n"
"}\n";
const char expected[] = "void foo ( const char str [ ] ) {\n"
"const char * p ; p = str ;\n"
"if ( str [ 0 ] == 0 ) {\n"
"}\n"
"}";
ASSERT_EQUALS(expected, tokenizeAndStringify(code, true));
}
void simplifyKnownVariables32() {
{
const char code[] = "void foo() {\n"
" const int x = 0;\n"
" bar(0,x);\n"
"}\n";
const char expected[] = "void foo ( ) {\n\nbar ( 0 , 0 ) ;\n}";
ASSERT_EQUALS(expected, tokenizeAndStringify(code, true));
}
{
const char code[] = "static int const SZ = 22; char str[SZ];\n";
ASSERT_EQUALS("char str [ 22 ] ;", tokenizeAndStringify(code,true));
}
}
void simplifyKnownVariables33() {
const char code[] = "static void foo(struct Foo *foo) {\n"
" foo->a = 23;\n"
" x[foo->a] = 0;\n"
"}\n";
const char expected[] = "static void foo ( struct Foo * foo ) {\n"
"foo . a = 23 ;\n"
"x [ 23 ] = 0 ;\n"
"}";
ASSERT_EQUALS(expected, tokenizeAndStringify(code, true));
}
void simplifyKnownVariables34() { void simplifyKnownVariables34() {
const char code[] = "void f() {\n" const char code[] = "void f() {\n"
" int x = 10;\n" " int x = 10;\n"
@ -4106,13 +3695,6 @@ private:
} }
void simplifyKnownVariables36() { void simplifyKnownVariables36() {
// Ticket #2304
const char code[] = "void f() {"
" const char *q = \"hello\";"
" strcpy(p, q);"
"}";
const char expected[] = "void f ( ) { const char * q ; q = \"hello\" ; strcpy ( p , \"hello\" ) ; }";
ASSERT_EQUALS(expected, tokenizeAndStringify(code, true));
// Ticket #5972 // Ticket #5972
const char code2[] = "void f() {" const char code2[] = "void f() {"
@ -4123,50 +3705,7 @@ private:
ASSERT_EQUALS(expected2, tokenizeAndStringify(code2, true)); ASSERT_EQUALS(expected2, tokenizeAndStringify(code2, true));
} }
void simplifyKnownVariables39() {
// Ticket #2296 - simplify pointer alias 'delete p;'
{
const char code[] = "void f() {\n"
" int *x;\n"
" int *y = x;\n"
" delete y;\n"
"}";
ASSERT_EQUALS("void f ( ) {\nint * x ;\nint * y ; y = x ;\ndelete x ;\n}", tokenizeAndStringify(code, true));
}
{
const char code[] = "void f() {\n"
" int *x;\n"
" int *y = x;\n"
" delete [] y;\n"
"}";
ASSERT_EQUALS("void f ( ) {\nint * x ;\nint * y ; y = x ;\ndelete [ ] x ;\n}", tokenizeAndStringify(code, true));
}
}
void simplifyKnownVariables41() {
const char code[] = "void f() {\n"
" int x = 0;\n"
" const int *p; p = &x;\n"
" if (p) { return 0; }\n"
"}";
ASSERT_EQUALS("void f ( ) {\nint x ; x = 0 ;\nconst int * p ; p = & x ;\nif ( & x ) { return 0 ; }\n}", tokenizeAndStringify(code, true));
}
void simplifyKnownVariables42() { void simplifyKnownVariables42() {
{
const char code[] = "void f() {\n"
" char str1[10], str2[10];\n"
" strcpy(str1, \"abc\");\n"
" strcpy(str2, str1);\n"
"}";
const char expected[] = "void f ( ) {\n"
"char str1 [ 10 ] ; char str2 [ 10 ] ;\n"
"strcpy ( str1 , \"abc\" ) ;\n"
"strcpy ( str2 , \"abc\" ) ;\n"
"}";
ASSERT_EQUALS(expected, tokenizeAndStringify(code, true));
}
{ {
const char code[] = "void f() {\n" const char code[] = "void f() {\n"
" char a[10];\n" " char a[10];\n"
@ -4261,20 +3800,6 @@ private:
ASSERT_EQUALS(expected, tokenizeAndStringify(code, true)); ASSERT_EQUALS(expected, tokenizeAndStringify(code, true));
} }
void simplifyKnownVariables45() {
const char code[] = "class Fred {\n"
"private:\n"
" const static int NUM = 2;\n"
" int array[NUM];\n"
"}";
const char expected[] = "class Fred {\n"
"private:\n"
"\n"
"int array [ 2 ] ;\n"
"}";
ASSERT_EQUALS(expected, tokenizeAndStringify(code, true));
}
void simplifyKnownVariables46() { void simplifyKnownVariables46() {
const char code[] = "void f() {\n" const char code[] = "void f() {\n"
" int x = 0;\n" " int x = 0;\n"
@ -4335,45 +3860,6 @@ private:
} }
void simplifyKnownVariables50() { // #4066 void simplifyKnownVariables50() { // #4066
{
const char code[] = "void f() {\n"
" char str1[10], str2[10];\n"
" sprintf(str1, \"%%\");\n"
" strcpy(str2, str1);\n"
"}";
const char expected[] = "void f ( ) {\n"
"char str1 [ 10 ] ; char str2 [ 10 ] ;\n"
"sprintf ( str1 , \"%%\" ) ;\n"
"strcpy ( str2 , \"%\" ) ;\n"
"}";
ASSERT_EQUALS(expected, tokenizeAndStringify(code, true));
}
{
const char code[] = "void f() {\n"
" char str1[25], str2[25];\n"
" sprintf(str1, \"abcdef%%%% and %% and %\");\n"
" strcpy(str2, str1);\n"
"}";
const char expected[] = "void f ( ) {\n"
"char str1 [ 25 ] ; char str2 [ 25 ] ;\n"
"sprintf ( str1 , \"abcdef%%%% and %% and %\" ) ;\n"
"strcpy ( str2 , \"abcdef%% and % and %\" ) ;\n"
"}";
ASSERT_EQUALS(expected, tokenizeAndStringify(code, true));
}
{
const char code[] = "void f() {\n"
" char str1[10], str2[10];\n"
" sprintf(str1, \"abc\");\n"
" strcpy(str2, str1);\n"
"}";
const char expected[] = "void f ( ) {\n"
"char str1 [ 10 ] ; char str2 [ 10 ] ;\n"
"sprintf ( str1 , \"abc\" ) ;\n"
"strcpy ( str2 , \"abc\" ) ;\n"
"}";
ASSERT_EQUALS(expected, tokenizeAndStringify(code, true));
}
{ {
//don't simplify '&x'! //don't simplify '&x'!
const char code[] = "const char * foo ( ) {\n" const char code[] = "const char * foo ( ) {\n"
@ -4425,21 +3911,10 @@ private:
ASSERT_THROW(tokenizeAndStringify(code, true), InternalError); ASSERT_THROW(tokenizeAndStringify(code, true), InternalError);
} }
void simplifyKnownVariables53() { // references
ASSERT_EQUALS("void f ( ) { int x ; x = abc ( ) ; }", tokenizeAndStringify("void f() { int x; int &ref=x; ref=abc(); }", true));
ASSERT_EQUALS("void f ( ) { int * p ; p = abc ( ) ; }", tokenizeAndStringify("void f() { int *p; int *&ref=p; ref=abc(); }", true));
}
void simplifyKnownVariables54() { // #4913 void simplifyKnownVariables54() { // #4913
ASSERT_EQUALS("void f ( int * p ) { * -- p = 0 ; * p = 0 ; }", tokenizeAndStringify("void f(int*p) { *--p=0; *p=0; }", true)); ASSERT_EQUALS("void f ( int * p ) { * -- p = 0 ; * p = 0 ; }", tokenizeAndStringify("void f(int*p) { *--p=0; *p=0; }", true));
} }
void simplifyKnownVariables55() { // pointer alias
ASSERT_EQUALS("void f ( ) { int a ; int * p ; if ( a > 0 ) { } }", tokenizeAndStringify("void f() { int a; int *p=&a; if (*p>0) {} }", true));
ASSERT_EQUALS("void f ( ) { int a ; struct AB ab ; ab . a = & a ; if ( a > 0 ) { } }", tokenizeAndStringify("void f() { int a; struct AB ab; ab.a = &a; if (*ab.a>0) {} }", true));
ASSERT_EQUALS("void f ( ) { int a ; int * p ; if ( x > a ) { } }", tokenizeAndStringify("void f() { int a; int *p=&a; if (x>*p) {} }", true));
}
void simplifyKnownVariables56() { // ticket #5301 - >> void simplifyKnownVariables56() { // ticket #5301 - >>
ASSERT_EQUALS("void f ( ) { int a ; a = 0 ; int b ; b = 0 ; * p >> a >> b ; return a / b ; }", ASSERT_EQUALS("void f ( ) { int a ; a = 0 ; int b ; b = 0 ; * p >> a >> b ; return a / b ; }",
tokenizeAndStringify("void f() { int a=0,b=0; *p>>a>>b; return a/b; }", true)); tokenizeAndStringify("void f() { int a=0,b=0; *p>>a>>b; return a/b; }", true));
@ -4485,21 +3960,6 @@ private:
"}", tokenizeAndStringify(code, true)); "}", tokenizeAndStringify(code, true));
} }
void simplifyKnownVariables60() { // #6829
const char code[] = "void f() {\n"
" int i = 1;\n"
" const int * const constPtrToConst = &i;\n"
" std::cout << *constPtrToConst << std::endl;\n"
" std::cout << constPtrToConst << std::endl;\n"
"}";
ASSERT_EQUALS("void f ( ) {\n"
"int i ; i = 1 ;\n"
"const int * const constPtrToConst ; constPtrToConst = & i ;\n"
"std :: cout << i << std :: endl ;\n"
"std :: cout << & i << std :: endl ;\n"
"}", tokenizeAndStringify(code, true));
}
void simplifyKnownVariables61() { // #7805 void simplifyKnownVariables61() { // #7805
tokenizeAndStringify("static const int XX = 0;\n" tokenizeAndStringify("static const int XX = 0;\n"
"enum E { XX };\n" "enum E { XX };\n"
@ -4679,22 +4139,6 @@ private:
ASSERT_EQUALS("static int x ; void f ( ) { x = 123 ; while ( ! x ) { dostuff ( ) ; } }", tokenizeAndStringify(code,true)); ASSERT_EQUALS("static int x ; void f ( ) { x = 123 ; while ( ! x ) { dostuff ( ) ; } }", tokenizeAndStringify(code,true));
} }
void simplifyKnownVariablesPointerAliasFunctionCall() { // #7440
const char code[] = "int main() {\n"
" char* data = new char[100];\n"
" char** dataPtr = &data;\n"
" printf(\"test\");\n"
" delete [] *dataPtr;\n"
"}";
const char exp[] = "int main ( ) {\n"
"char * data ; data = new char [ 100 ] ;\n"
"char * * dataPtr ; dataPtr = & data ;\n"
"printf ( \"test\" ) ;\n"
"delete [ ] data ;\n"
"}";
ASSERT_EQUALS(exp, tokenizeAndStringify(code, /*simplify=*/ true));
}
void simplifyKnownVariablesNamespace() { void simplifyKnownVariablesNamespace() {
{ // #10059 { // #10059
const char code[] = "namespace N {\n" const char code[] = "namespace N {\n"
@ -4785,25 +4229,6 @@ private:
} }
} }
void simplify_constants2() {
const char code[] =
"void f( Foo &foo, Foo *foo2 ) {\n"
"const int a = 45;\n"
"foo.a=a+a;\n"
"foo2->a=a;\n"
"}";
ASSERT_EQUALS("void f ( Foo & foo , Foo * foo2 ) { foo . a = 90 ; foo2 . a = 45 ; }", tok(code));
}
void simplify_constants4() {
const char code[] = "static const int bSize = 4;\n"
"static const int aSize = 50;\n"
"x = bSize;\n"
"y = aSize;\n";
ASSERT_EQUALS("x = 4 ; y = 50 ;", tok(code));
}
void simplify_constants6() { // Ticket #5625 void simplify_constants6() { // Ticket #5625
{ {
const char code[] = "template < class T > struct foo ;\n" const char code[] = "template < class T > struct foo ;\n"