Tokenizer: Added new function isFunctionParameterPassedByValue that check if a parameter is passed by value

This commit is contained in:
Daniel Marjamäki 2012-06-24 13:39:14 +02:00
parent 8c39b95aae
commit 8af044255d
3 changed files with 107 additions and 0 deletions

View File

@ -6089,6 +6089,15 @@ bool Tokenizer::simplifyKnownVariablesSimplify(Token **tok2, Token *tok3, unsign
ret = true; ret = true;
} }
// parameter in function call..
if (tok3->varId() == varid && Token::Match(tok3->previous(), "[(,] %var% [,)]")) {
// If the parameter is passed by value then simplify it
if (isFunctionParameterPassedByValue(tok3)) {
tok3->str(value);
ret = true;
}
}
// Variable is used somehow in a non-defined pattern => bail out // Variable is used somehow in a non-defined pattern => bail out
if (tok3->varId() == varid) { if (tok3->varId() == varid) {
// This is a really generic bailout so let's try to avoid this. // This is a really generic bailout so let's try to avoid this.
@ -7298,6 +7307,73 @@ const Token *Tokenizer::getFunctionTokenByName(const char funcname[]) const
return NULL; return NULL;
} }
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?
unsigned int paranthesis = 1;
unsigned int parameter = 1;
for (ftok = fpar; ftok; ftok = ftok->previous()) {
if (ftok->str() == "(") {
--paranthesis;
if (paranthesis == 0) {
break;
}
} else if (ftok->str() == ")") {
++paranthesis;
} else if (paranthesis == 1 && ftok->str() == ",") {
++parameter;
} else if (Token::Match(ftok, "[;{}]")) {
break;
}
}
// Is this a function call?
if (ftok && Token::Match(ftok->tokAt(-2), "[;{}=] %var% (")) {
const std::string functionName(ftok->previous()->str() + " (");
// Locate function declaration..
unsigned int indentlevel = 0;
for (const Token *tok = tokens(); tok; tok = tok->next()) {
if (tok->str() == "{")
++indentlevel;
else if (tok->str() == "}")
indentlevel = (indentlevel > 0) ? indentlevel - 1U : 0U;
else if (indentlevel == 0 && tok->isName() && Token::simpleMatch(tok, functionName.c_str())) {
// Goto parameter
tok = tok->tokAt(2);
unsigned 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;
}
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------

View File

@ -160,6 +160,14 @@ public:
*/ */
const Token *getFunctionTokenByName(const char funcname[]) const; const Token *getFunctionTokenByName(const char funcname[]) const;
/**
* Try to determine if function parameter is passed by value by looking
* at the function declaration.
* @param fpar token for function parameter in the function call
* @return true if the parameter is passed by value. if unsure, false is returned
*/
bool isFunctionParameterPassedByValue(const Token *fpar) const;
/** /**
* get error messages that the tokenizer generate * get error messages that the tokenizer generate
*/ */

View File

@ -168,6 +168,7 @@ private:
TEST_CASE(simplifyKnownVariablesBailOutSwitchBreak); // ticket #2324 TEST_CASE(simplifyKnownVariablesBailOutSwitchBreak); // ticket #2324
TEST_CASE(simplifyKnownVariablesFloat); // #2454 - float variable TEST_CASE(simplifyKnownVariablesFloat); // #2454 - float variable
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(simplifyExternC); TEST_CASE(simplifyExternC);
TEST_CASE(varid1); TEST_CASE(varid1);
@ -2515,6 +2516,28 @@ private:
ASSERT_EQUALS(expected, tokenizeAndStringify(code,true)); ASSERT_EQUALS(expected, tokenizeAndStringify(code,true));
} }
void simplifyKnownVariablesFunctionCalls() {
{
const char code[] = "void a(int x);" // <- x is passed by value
"void b() {"
" int x = 123;"
" a(x);" // <- replace with a(123);
"}";
const char expected[] = "void a ( int x ) ; void b ( ) { a ( 123 ) ; }";
ASSERT_EQUALS(expected, tokenizeAndStringify(code,true));
}
{
const char code[] = "void a(int &x);" // <- x is passed by reference
"void b() {"
" int x = 123;"
" a(x);" // <- don't replace with a(123);
"}";
const char expected[] = "void a ( int & x ) ; void b ( ) { int x ; x = 123 ; a ( x ) ; }";
ASSERT_EQUALS(expected, tokenizeAndStringify(code,true));
}
}
void simplifyKnownVariablesClassMember() { void simplifyKnownVariablesClassMember() {
// Ticket #2815 // Ticket #2815
{ {